diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-05-09 08:51:53 -0400 |
---|---|---|
committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-05-09 22:32:34 -0400 |
commit | d240e06713007bba309b074a386b7072b73c31a6 (patch) | |
tree | 3c9133ae5b349aeec8c0a93338b9dd13b9c9dac1 /fs | |
parent | cdce214e39814fd46d47e0e660ca3ddf3fdce8a6 (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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nilfs2/super.c | 57 |
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); |