Skip to content

Commit 829b37b

Browse files
committed
ext4: avoid race conditions when remounting with options that change dax
Trying to change dax mount options when remounting could allow mount options to be enabled for a small amount of time, and then the mount option change would be reverted. In the case of "mount -o remount,dax", this can cause a race where files would temporarily treated as DAX --- and then not. Cc: [email protected] Reported-by: [email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 68cd449 commit 829b37b

File tree

1 file changed

+24
-18
lines changed

1 file changed

+24
-18
lines changed

fs/ext4/super.c

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,16 +2104,40 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
21042104
switch (token) {
21052105
case Opt_dax:
21062106
case Opt_dax_always:
2107+
if (is_remount &&
2108+
(!(sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS) ||
2109+
(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_NEVER))) {
2110+
fail_dax_change_remount:
2111+
ext4_msg(sb, KERN_ERR, "can't change "
2112+
"dax mount option while remounting");
2113+
return -1;
2114+
}
2115+
if (is_remount &&
2116+
(test_opt(sb, DATA_FLAGS) ==
2117+
EXT4_MOUNT_JOURNAL_DATA)) {
2118+
ext4_msg(sb, KERN_ERR, "can't mount with "
2119+
"both data=journal and dax");
2120+
return -1;
2121+
}
21072122
ext4_msg(sb, KERN_WARNING,
21082123
"DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
21092124
sbi->s_mount_opt |= EXT4_MOUNT_DAX_ALWAYS;
21102125
sbi->s_mount_opt2 &= ~EXT4_MOUNT2_DAX_NEVER;
21112126
break;
21122127
case Opt_dax_never:
2128+
if (is_remount &&
2129+
(!(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_NEVER) ||
2130+
(sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS)))
2131+
goto fail_dax_change_remount;
21132132
sbi->s_mount_opt2 |= EXT4_MOUNT2_DAX_NEVER;
21142133
sbi->s_mount_opt &= ~EXT4_MOUNT_DAX_ALWAYS;
21152134
break;
21162135
case Opt_dax_inode:
2136+
if (is_remount &&
2137+
((sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS) ||
2138+
(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_NEVER) ||
2139+
!(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_INODE)))
2140+
goto fail_dax_change_remount;
21172141
sbi->s_mount_opt &= ~EXT4_MOUNT_DAX_ALWAYS;
21182142
sbi->s_mount_opt2 &= ~EXT4_MOUNT2_DAX_NEVER;
21192143
/* Strictly for printing options */
@@ -5454,12 +5478,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
54545478
err = -EINVAL;
54555479
goto restore_opts;
54565480
}
5457-
if (test_opt(sb, DAX_ALWAYS)) {
5458-
ext4_msg(sb, KERN_ERR, "can't mount with "
5459-
"both data=journal and dax");
5460-
err = -EINVAL;
5461-
goto restore_opts;
5462-
}
54635481
} else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) {
54645482
if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
54655483
ext4_msg(sb, KERN_ERR, "can't mount with "
@@ -5475,18 +5493,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
54755493
goto restore_opts;
54765494
}
54775495

5478-
if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_DAX_ALWAYS ||
5479-
(sbi->s_mount_opt2 ^ old_opts.s_mount_opt2) & EXT4_MOUNT2_DAX_NEVER ||
5480-
(sbi->s_mount_opt2 ^ old_opts.s_mount_opt2) & EXT4_MOUNT2_DAX_INODE) {
5481-
ext4_msg(sb, KERN_WARNING, "warning: refusing change of "
5482-
"dax mount option with busy inodes while remounting");
5483-
sbi->s_mount_opt &= ~EXT4_MOUNT_DAX_ALWAYS;
5484-
sbi->s_mount_opt |= old_opts.s_mount_opt & EXT4_MOUNT_DAX_ALWAYS;
5485-
sbi->s_mount_opt2 &= ~(EXT4_MOUNT2_DAX_NEVER | EXT4_MOUNT2_DAX_INODE);
5486-
sbi->s_mount_opt2 |= old_opts.s_mount_opt2 &
5487-
(EXT4_MOUNT2_DAX_NEVER | EXT4_MOUNT2_DAX_INODE);
5488-
}
5489-
54905496
if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
54915497
ext4_abort(sb, EXT4_ERR_ESHUTDOWN, "Abort forced by user");
54925498

0 commit comments

Comments
 (0)