Commit d240e067 authored by Ryusuke Konishi's avatar Ryusuke Konishi

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: default avatarRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
parent cdce214e
...@@ -754,9 +754,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, ...@@ -754,9 +754,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
goto failed_sbi; goto failed_sbi;
} }
cno = sbi->s_snapshot_cno; cno = sbi->s_snapshot_cno;
} else }
/* Read-only mount */
sbi->s_snapshot_cno = cno;
} }
err = nilfs_attach_checkpoint(sbi, cno); err = nilfs_attach_checkpoint(sbi, cno);
...@@ -825,7 +823,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) ...@@ -825,7 +823,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
struct the_nilfs *nilfs = sbi->s_nilfs; struct the_nilfs *nilfs = sbi->s_nilfs;
unsigned long old_sb_flags; unsigned long old_sb_flags;
struct nilfs_mount_options old_opts; struct nilfs_mount_options old_opts;
int err; int was_snapshot, err;
lock_kernel(); lock_kernel();
...@@ -833,6 +831,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) ...@@ -833,6 +831,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
old_sb_flags = sb->s_flags; old_sb_flags = sb->s_flags;
old_opts.mount_opt = sbi->s_mount_opt; old_opts.mount_opt = sbi->s_mount_opt;
old_opts.snapshot_cno = sbi->s_snapshot_cno; old_opts.snapshot_cno = sbi->s_snapshot_cno;
was_snapshot = nilfs_test_opt(sbi, SNAPSHOT);
if (!parse_options(data, sb)) { if (!parse_options(data, sb)) {
err = -EINVAL; err = -EINVAL;
...@@ -840,20 +839,32 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) ...@@ -840,20 +839,32 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
} }
sb->s_flags = (sb->s_flags & ~MS_POSIXACL); sb->s_flags = (sb->s_flags & ~MS_POSIXACL);
if ((*flags & MS_RDONLY) && err = -EINVAL;
sbi->s_snapshot_cno != old_opts.snapshot_cno) { if (was_snapshot) {
printk(KERN_WARNING "NILFS (device %s): couldn't " if (!(*flags & MS_RDONLY)) {
printk(KERN_ERR "NILFS (device %s): cannot remount "
"snapshot read/write.\n",
sb->s_id);
goto restore_opts;
} else if (sbi->s_snapshot_cno != old_opts.snapshot_cno) {
printk(KERN_ERR "NILFS (device %s): cannot "
"remount to a different snapshot.\n", "remount to a different snapshot.\n",
sb->s_id); sb->s_id);
err = -EINVAL;
goto restore_opts; goto restore_opts;
} }
} else {
if (nilfs_test_opt(sbi, SNAPSHOT)) {
printk(KERN_ERR "NILFS (device %s): cannot change "
"a regular mount to a snapshot.\n",
sb->s_id);
goto restore_opts;
}
}
if (!nilfs_valid_fs(nilfs)) { if (!nilfs_valid_fs(nilfs)) {
printk(KERN_WARNING "NILFS (device %s): couldn't " printk(KERN_WARNING "NILFS (device %s): couldn't "
"remount because the filesystem is in an " "remount because the filesystem is in an "
"incomplete recovery state.\n", sb->s_id); "incomplete recovery state.\n", sb->s_id);
err = -EINVAL;
goto restore_opts; goto restore_opts;
} }
...@@ -864,9 +875,6 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) ...@@ -864,9 +875,6 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
nilfs_detach_segment_constructor(sbi); nilfs_detach_segment_constructor(sbi);
sb->s_flags |= MS_RDONLY; sb->s_flags |= MS_RDONLY;
sbi->s_snapshot_cno = nilfs_last_cno(nilfs);
/* nilfs_set_opt(sbi, SNAPSHOT); */
/* /*
* Remounting a valid RW partition RDONLY, so set * Remounting a valid RW partition RDONLY, so set
* the RDONLY flag and then mark the partition as valid again. * 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,24 +893,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
* store the current valid flag. (It may have been changed * store the current valid flag. (It may have been changed
* by fsck since we originally mounted the partition.) * by fsck since we originally mounted the partition.)
*/ */
if (nilfs->ns_current && nilfs->ns_current != sbi) {
printk(KERN_WARNING "NILFS (device %s): couldn't "
"remount because an RW-mount exists.\n",
sb->s_id);
err = -EBUSY;
goto restore_opts;
}
if (sbi->s_snapshot_cno != nilfs_last_cno(nilfs)) {
printk(KERN_WARNING "NILFS (device %s): couldn't "
"remount because the current RO-mount is not "
"the latest one.\n",
sb->s_id);
err = -EINVAL;
goto restore_opts;
}
sb->s_flags &= ~MS_RDONLY; sb->s_flags &= ~MS_RDONLY;
nilfs_clear_opt(sbi, SNAPSHOT);
sbi->s_snapshot_cno = 0;
err = nilfs_attach_segment_constructor(sbi); err = nilfs_attach_segment_constructor(sbi);
if (err) if (err)
...@@ -911,8 +902,6 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) ...@@ -911,8 +902,6 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
down_write(&nilfs->ns_sem); down_write(&nilfs->ns_sem);
nilfs_setup_super(sbi); nilfs_setup_super(sbi);
up_write(&nilfs->ns_sem); up_write(&nilfs->ns_sem);
nilfs->ns_current = sbi;
} }
out: out:
up_write(&nilfs->ns_super_sem); up_write(&nilfs->ns_super_sem);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment