diff options
| -rw-r--r-- | fs/super.c | 18 | 
1 files changed, 15 insertions, 3 deletions
diff --git a/fs/super.c b/fs/super.c index aff046b0fe7..903896ec7c7 100644 --- a/fs/super.c +++ b/fs/super.c @@ -568,7 +568,7 @@ out:  int do_remount_sb(struct super_block *sb, int flags, void *data, int force)  {  	int retval; -	int remount_rw; +	int remount_rw, remount_ro;  	if (sb->s_frozen != SB_UNFROZEN)  		return -EBUSY; @@ -583,9 +583,12 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)  	shrink_dcache_sb(sb);  	sync_filesystem(sb); +	remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY); +	remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY); +  	/* 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)) { +	if (remount_ro) {  		if (force)  			mark_files_ro(sb);  		else if (!fs_may_remount_ro(sb)) @@ -594,7 +597,6 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)  		if (retval < 0 && retval != -ENOSYS)  			return -EBUSY;  	} -	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); @@ -604,6 +606,16 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)  	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);  	if (remount_rw)  		vfs_dq_quota_on_remount(sb); +	/* +	 * Some filesystems modify their metadata via some other path than the +	 * bdev buffer cache (eg. use a private mapping, or directories in +	 * pagecache, etc). Also file data modifications go via their own +	 * mappings. So If we try to mount readonly then copy the filesystem +	 * from bdev, we could get stale data, so invalidate it to give a best +	 * effort at coherency. +	 */ +	if (remount_ro && sb->s_bdev) +		invalidate_bdev(sb->s_bdev);  	return 0;  }  |