aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-05-09 08:51:53 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-05-09 22:32:34 -0400
commitd240e06713007bba309b074a386b7072b73c31a6 (patch)
tree3c9133ae5b349aeec8c0a93338b9dd13b9c9dac1
parentcdce214e39814fd46d47e0e660ca3ddf3fdce8a6 (diff)
nilfs2: disallow remount of snapshot from/to a regular mount
Snapshots and regular ro/rw mounts are essentially-different within the meaning whether the checkpoint is static or not and is marked with a snapshot flag or not. The current implemenation, however, allows to remount a snapshot to a regular rw-mount if the checkpoint number equals the latest one. This transition is actually impossible since changing a checkpoint to a snapshot makes another checkpoint, thus the condition is never satisfied. This fixes the weird state of affairs, and specifically separates snapshots and regular rw/ro-mounts. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
-rw-r--r--fs/nilfs2/super.c57
1 files changed, 23 insertions, 34 deletions
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index c88e66417330..03b34b738993 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -754,9 +754,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
754 goto failed_sbi; 754 goto failed_sbi;
755 } 755 }
756 cno = sbi->s_snapshot_cno; 756 cno = sbi->s_snapshot_cno;
757 } else 757 }
758 /* Read-only mount */
759 sbi->s_snapshot_cno = cno;
760 } 758 }
761 759
762 err = nilfs_attach_checkpoint(sbi, cno); 760 err = nilfs_attach_checkpoint(sbi, cno);
@@ -825,7 +823,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
825 struct the_nilfs *nilfs = sbi->s_nilfs; 823 struct the_nilfs *nilfs = sbi->s_nilfs;
826 unsigned long old_sb_flags; 824 unsigned long old_sb_flags;
827 struct nilfs_mount_options old_opts; 825 struct nilfs_mount_options old_opts;
828 int err; 826 int was_snapshot, err;
829 827
830 lock_kernel(); 828 lock_kernel();
831 829
@@ -833,6 +831,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
833 old_sb_flags = sb->s_flags; 831 old_sb_flags = sb->s_flags;
834 old_opts.mount_opt = sbi->s_mount_opt; 832 old_opts.mount_opt = sbi->s_mount_opt;
835 old_opts.snapshot_cno = sbi->s_snapshot_cno; 833 old_opts.snapshot_cno = sbi->s_snapshot_cno;
834 was_snapshot = nilfs_test_opt(sbi, SNAPSHOT);
836 835
837 if (!parse_options(data, sb)) { 836 if (!parse_options(data, sb)) {
838 err = -EINVAL; 837 err = -EINVAL;
@@ -840,20 +839,32 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
840 } 839 }
841 sb->s_flags = (sb->s_flags & ~MS_POSIXACL); 840 sb->s_flags = (sb->s_flags & ~MS_POSIXACL);
842 841
843 if ((*flags & MS_RDONLY) && 842 err = -EINVAL;
844 sbi->s_snapshot_cno != old_opts.snapshot_cno) { 843 if (was_snapshot) {
845 printk(KERN_WARNING "NILFS (device %s): couldn't " 844 if (!(*flags & MS_RDONLY)) {
846 "remount to a different snapshot.\n", 845 printk(KERN_ERR "NILFS (device %s): cannot remount "
847 sb->s_id); 846 "snapshot read/write.\n",
848 err = -EINVAL; 847 sb->s_id);
849 goto restore_opts; 848 goto restore_opts;
849 } else if (sbi->s_snapshot_cno != old_opts.snapshot_cno) {
850 printk(KERN_ERR "NILFS (device %s): cannot "
851 "remount to a different snapshot.\n",
852 sb->s_id);
853 goto restore_opts;
854 }
855 } else {
856 if (nilfs_test_opt(sbi, SNAPSHOT)) {
857 printk(KERN_ERR "NILFS (device %s): cannot change "
858 "a regular mount to a snapshot.\n",
859 sb->s_id);
860 goto restore_opts;
861 }
850 } 862 }
851 863
852 if (!nilfs_valid_fs(nilfs)) { 864 if (!nilfs_valid_fs(nilfs)) {
853 printk(KERN_WARNING "NILFS (device %s): couldn't " 865 printk(KERN_WARNING "NILFS (device %s): couldn't "
854 "remount because the filesystem is in an " 866 "remount because the filesystem is in an "
855 "incomplete recovery state.\n", sb->s_id); 867 "incomplete recovery state.\n", sb->s_id);
856 err = -EINVAL;
857 goto restore_opts; 868 goto restore_opts;
858 } 869 }
859 870
@@ -864,9 +875,6 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
864 nilfs_detach_segment_constructor(sbi); 875 nilfs_detach_segment_constructor(sbi);
865 sb->s_flags |= MS_RDONLY; 876 sb->s_flags |= MS_RDONLY;
866 877
867 sbi->s_snapshot_cno = nilfs_last_cno(nilfs);
868 /* nilfs_set_opt(sbi, SNAPSHOT); */
869
870 /* 878 /*
871 * Remounting a valid RW partition RDONLY, so set 879 * Remounting a valid RW partition RDONLY, so set
872 * the RDONLY flag and then mark the partition as valid again. 880 * the RDONLY flag and then mark the partition as valid again.
@@ -885,24 +893,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
885 * store the current valid flag. (It may have been changed 893 * store the current valid flag. (It may have been changed
886 * by fsck since we originally mounted the partition.) 894 * by fsck since we originally mounted the partition.)
887 */ 895 */
888 if (nilfs->ns_current && nilfs->ns_current != sbi) {
889 printk(KERN_WARNING "NILFS (device %s): couldn't "
890 "remount because an RW-mount exists.\n",
891 sb->s_id);
892 err = -EBUSY;
893 goto restore_opts;
894 }
895 if (sbi->s_snapshot_cno != nilfs_last_cno(nilfs)) {
896 printk(KERN_WARNING "NILFS (device %s): couldn't "
897 "remount because the current RO-mount is not "
898 "the latest one.\n",
899 sb->s_id);
900 err = -EINVAL;
901 goto restore_opts;
902 }
903 sb->s_flags &= ~MS_RDONLY; 896 sb->s_flags &= ~MS_RDONLY;
904 nilfs_clear_opt(sbi, SNAPSHOT);
905 sbi->s_snapshot_cno = 0;
906 897
907 err = nilfs_attach_segment_constructor(sbi); 898 err = nilfs_attach_segment_constructor(sbi);
908 if (err) 899 if (err)
@@ -911,8 +902,6 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
911 down_write(&nilfs->ns_sem); 902 down_write(&nilfs->ns_sem);
912 nilfs_setup_super(sbi); 903 nilfs_setup_super(sbi);
913 up_write(&nilfs->ns_sem); 904 up_write(&nilfs->ns_sem);
914
915 nilfs->ns_current = sbi;
916 } 905 }
917 out: 906 out:
918 up_write(&nilfs->ns_super_sem); 907 up_write(&nilfs->ns_super_sem);