diff --git a/fs/namespace.c b/fs/namespace.c index c768f73..a216fb3 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -194,7 +194,7 @@ int __mnt_is_readonly(struct vfsmount *mnt) { if (mnt->mnt_flags & MNT_READONLY) return 1; - if (mnt->mnt_sb->s_flags & MS_RDONLY) + if (mnt->mnt_sb->s_flags & (MS_RDONLY| MS_RO_REMOUNT)) return 1; return 0; } diff --git a/fs/super.c b/fs/super.c index aff046b..756fe88 100644 --- a/fs/super.c +++ b/fs/super.c @@ -569,42 +569,51 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) { int retval; int remount_rw; + int remount_ro; if (sb->s_frozen != SB_UNFROZEN) return -EBUSY; - + remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY); #ifdef CONFIG_BLOCK if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev)) return -EACCES; #endif - if (flags & MS_RDONLY) acct_auto_close(sb); - shrink_dcache_sb(sb); - sync_filesystem(sb); /* If we are remounting RDONLY and current sb is read/write, make sure there are no rw files opened */ - if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) { + retval = -EBUSY; + if (remount_ro) { + /* Prevent new writers before check */ + sb->s_flags |= MS_RO_REMOUNT; if (force) mark_files_ro(sb); else if (!fs_may_remount_ro(sb)) - return -EBUSY; + goto out; + } + shrink_dcache_sb(sb); + sync_filesystem(sb); + + if (remount_ro) { retval = vfs_dq_off(sb, 1); if (retval < 0 && retval != -ENOSYS) - return -EBUSY; + goto out; } remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY); if (sb->s_op->remount_fs) { retval = sb->s_op->remount_fs(sb, &flags, data); if (retval) - return retval; + goto out; } sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); if (remount_rw) vfs_dq_quota_on_remount(sb); - return 0; +out: + if (remount_ro) + sb->s_flags = (sb->s_flags & ~MS_RO_REMOUNT); + return retval; } static void do_emergency_remount(struct work_struct *work) diff --git a/include/linux/fs.h b/include/linux/fs.h index b1bcb27..a613875 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -208,6 +208,9 @@ struct inodes_stat_t { #define MS_STRICTATIME (1<<24) /* Always perform atime updates */ #define MS_ACTIVE (1<<30) #define MS_NOUSER (1<<31) +#define MS_RO_REMOUNT MS_REMOUNT /* Alter flags from rw=>ro of mounted FS. + Not conflicting with MS_REMOUNT because + it never stored in sb->s_flags */ /* * Superblock flags that can be altered by MS_REMOUNT