diff options
author | David Howells <dhowells@redhat.com> | 2018-11-04 09:28:36 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2019-01-30 17:44:26 -0500 |
commit | 8d0347f6c3a9d4953ddd636a31c6584da082e084 (patch) | |
tree | a8dec0e9d854bad8732ae41084e6f7c980713758 /fs/super.c | |
parent | c9ce29ed795fae86e594844857fad1b0d3be85f4 (diff) |
convert do_remount_sb() to fs_context
Replace do_remount_sb() with a function, reconfigure_super(), that's
fs_context aware. The fs_context is expected to be parameterised already
and have ->root pointing to the superblock to be reconfigured.
A legacy wrapper is provided that is intended to be called from the
fs_context ops when those appear, but for now is called directly from
reconfigure_super(). This wrapper invokes the ->remount_fs() superblock op
for the moment. It is intended that the remount_fs() op will be phased
out.
The fs_context->purpose is set to FS_CONTEXT_FOR_RECONFIGURE to indicate
that the context is being used for reconfiguration.
do_umount_root() is provided to consolidate remount-to-R/O for umount and
emergency remount by creating a context and invoking reconfiguration.
do_remount(), do_umount() and do_emergency_remount_callback() are switched
to use the new process.
[AV -- fold UMOUNT and EMERGENCY_REMOUNT in; fixes the
umount / bug, gets rid of pointless complexity]
[AV -- set ->net_ns in all cases; nfs remount will need that]
[AV -- shift security_sb_remount() call into reconfigure_super(); the callers
that didn't do security_sb_remount() have NULL fc->security anyway, so it's
a no-op for them]
Signed-off-by: David Howells <dhowells@redhat.com>
Co-developed-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/super.c')
-rw-r--r-- | fs/super.c | 107 |
1 files changed, 73 insertions, 34 deletions
diff --git a/fs/super.c b/fs/super.c index 11e2a6cb3baf..50553233dd15 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -836,28 +836,35 @@ rescan: | |||
836 | } | 836 | } |
837 | 837 | ||
838 | /** | 838 | /** |
839 | * do_remount_sb - asks filesystem to change mount options. | 839 | * reconfigure_super - asks filesystem to change superblock parameters |
840 | * @sb: superblock in question | 840 | * @fc: The superblock and configuration |
841 | * @sb_flags: revised superblock flags | ||
842 | * @data: the rest of options | ||
843 | * @force: whether or not to force the change | ||
844 | * | 841 | * |
845 | * Alters the mount options of a mounted file system. | 842 | * Alters the configuration parameters of a live superblock. |
846 | */ | 843 | */ |
847 | int do_remount_sb(struct super_block *sb, int sb_flags, void *data, int force) | 844 | int reconfigure_super(struct fs_context *fc) |
848 | { | 845 | { |
846 | struct super_block *sb = fc->root->d_sb; | ||
849 | int retval; | 847 | int retval; |
850 | int remount_ro; | 848 | bool remount_ro = false; |
849 | bool force = fc->sb_flags & SB_FORCE; | ||
851 | 850 | ||
851 | if (fc->sb_flags_mask & ~MS_RMT_MASK) | ||
852 | return -EINVAL; | ||
852 | if (sb->s_writers.frozen != SB_UNFROZEN) | 853 | if (sb->s_writers.frozen != SB_UNFROZEN) |
853 | return -EBUSY; | 854 | return -EBUSY; |
854 | 855 | ||
856 | retval = security_sb_remount(sb, fc->security); | ||
857 | if (retval) | ||
858 | return retval; | ||
859 | |||
860 | if (fc->sb_flags_mask & SB_RDONLY) { | ||
855 | #ifdef CONFIG_BLOCK | 861 | #ifdef CONFIG_BLOCK |
856 | if (!(sb_flags & SB_RDONLY) && bdev_read_only(sb->s_bdev)) | 862 | if (!(fc->sb_flags & SB_RDONLY) && bdev_read_only(sb->s_bdev)) |
857 | return -EACCES; | 863 | return -EACCES; |
858 | #endif | 864 | #endif |
859 | 865 | ||
860 | remount_ro = (sb_flags & SB_RDONLY) && !sb_rdonly(sb); | 866 | remount_ro = (fc->sb_flags & SB_RDONLY) && !sb_rdonly(sb); |
867 | } | ||
861 | 868 | ||
862 | if (remount_ro) { | 869 | if (remount_ro) { |
863 | if (!hlist_empty(&sb->s_pins)) { | 870 | if (!hlist_empty(&sb->s_pins)) { |
@@ -868,13 +875,14 @@ int do_remount_sb(struct super_block *sb, int sb_flags, void *data, int force) | |||
868 | return 0; | 875 | return 0; |
869 | if (sb->s_writers.frozen != SB_UNFROZEN) | 876 | if (sb->s_writers.frozen != SB_UNFROZEN) |
870 | return -EBUSY; | 877 | return -EBUSY; |
871 | remount_ro = (sb_flags & SB_RDONLY) && !sb_rdonly(sb); | 878 | remount_ro = !sb_rdonly(sb); |
872 | } | 879 | } |
873 | } | 880 | } |
874 | shrink_dcache_sb(sb); | 881 | shrink_dcache_sb(sb); |
875 | 882 | ||
876 | /* If we are remounting RDONLY and current sb is read/write, | 883 | /* If we are reconfiguring to RDONLY and current sb is read/write, |
877 | make sure there are no rw files opened */ | 884 | * make sure there are no files open for writing. |
885 | */ | ||
878 | if (remount_ro) { | 886 | if (remount_ro) { |
879 | if (force) { | 887 | if (force) { |
880 | sb->s_readonly_remount = 1; | 888 | sb->s_readonly_remount = 1; |
@@ -886,17 +894,17 @@ int do_remount_sb(struct super_block *sb, int sb_flags, void *data, int force) | |||
886 | } | 894 | } |
887 | } | 895 | } |
888 | 896 | ||
889 | if (sb->s_op->remount_fs) { | 897 | retval = legacy_reconfigure(fc); |
890 | retval = sb->s_op->remount_fs(sb, &sb_flags, data); | 898 | if (retval) { |
891 | if (retval) { | 899 | if (!force) |
892 | if (!force) | 900 | goto cancel_readonly; |
893 | goto cancel_readonly; | 901 | /* If forced remount, go ahead despite any errors */ |
894 | /* If forced remount, go ahead despite any errors */ | 902 | WARN(1, "forced remount of a %s fs returned %i\n", |
895 | WARN(1, "forced remount of a %s fs returned %i\n", | 903 | sb->s_type->name, retval); |
896 | sb->s_type->name, retval); | ||
897 | } | ||
898 | } | 904 | } |
899 | sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (sb_flags & MS_RMT_MASK); | 905 | |
906 | WRITE_ONCE(sb->s_flags, ((sb->s_flags & ~fc->sb_flags_mask) | | ||
907 | (fc->sb_flags & fc->sb_flags_mask))); | ||
900 | /* Needs to be ordered wrt mnt_is_readonly() */ | 908 | /* Needs to be ordered wrt mnt_is_readonly() */ |
901 | smp_wmb(); | 909 | smp_wmb(); |
902 | sb->s_readonly_remount = 0; | 910 | sb->s_readonly_remount = 0; |
@@ -923,10 +931,15 @@ static void do_emergency_remount_callback(struct super_block *sb) | |||
923 | down_write(&sb->s_umount); | 931 | down_write(&sb->s_umount); |
924 | if (sb->s_root && sb->s_bdev && (sb->s_flags & SB_BORN) && | 932 | if (sb->s_root && sb->s_bdev && (sb->s_flags & SB_BORN) && |
925 | !sb_rdonly(sb)) { | 933 | !sb_rdonly(sb)) { |
926 | /* | 934 | struct fs_context *fc; |
927 | * What lock protects sb->s_flags?? | 935 | |
928 | */ | 936 | fc = fs_context_for_reconfigure(sb->s_root, |
929 | do_remount_sb(sb, SB_RDONLY, NULL, 1); | 937 | SB_RDONLY | SB_FORCE, SB_RDONLY); |
938 | if (!IS_ERR(fc)) { | ||
939 | if (parse_monolithic_mount_data(fc, NULL) == 0) | ||
940 | (void)reconfigure_super(fc); | ||
941 | put_fs_context(fc); | ||
942 | } | ||
930 | } | 943 | } |
931 | up_write(&sb->s_umount); | 944 | up_write(&sb->s_umount); |
932 | } | 945 | } |
@@ -1213,6 +1226,31 @@ struct dentry *mount_nodev(struct file_system_type *fs_type, | |||
1213 | } | 1226 | } |
1214 | EXPORT_SYMBOL(mount_nodev); | 1227 | EXPORT_SYMBOL(mount_nodev); |
1215 | 1228 | ||
1229 | static int reconfigure_single(struct super_block *s, | ||
1230 | int flags, void *data) | ||
1231 | { | ||
1232 | struct fs_context *fc; | ||
1233 | int ret; | ||
1234 | |||
1235 | /* The caller really need to be passing fc down into mount_single(), | ||
1236 | * then a chunk of this can be removed. [Bollocks -- AV] | ||
1237 | * Better yet, reconfiguration shouldn't happen, but rather the second | ||
1238 | * mount should be rejected if the parameters are not compatible. | ||
1239 | */ | ||
1240 | fc = fs_context_for_reconfigure(s->s_root, flags, MS_RMT_MASK); | ||
1241 | if (IS_ERR(fc)) | ||
1242 | return PTR_ERR(fc); | ||
1243 | |||
1244 | ret = parse_monolithic_mount_data(fc, data); | ||
1245 | if (ret < 0) | ||
1246 | goto out; | ||
1247 | |||
1248 | ret = reconfigure_super(fc); | ||
1249 | out: | ||
1250 | put_fs_context(fc); | ||
1251 | return ret; | ||
1252 | } | ||
1253 | |||
1216 | static int compare_single(struct super_block *s, void *p) | 1254 | static int compare_single(struct super_block *s, void *p) |
1217 | { | 1255 | { |
1218 | return 1; | 1256 | return 1; |
@@ -1230,13 +1268,14 @@ struct dentry *mount_single(struct file_system_type *fs_type, | |||
1230 | return ERR_CAST(s); | 1268 | return ERR_CAST(s); |
1231 | if (!s->s_root) { | 1269 | if (!s->s_root) { |
1232 | error = fill_super(s, data, flags & SB_SILENT ? 1 : 0); | 1270 | error = fill_super(s, data, flags & SB_SILENT ? 1 : 0); |
1233 | if (error) { | 1271 | if (!error) |
1234 | deactivate_locked_super(s); | 1272 | s->s_flags |= SB_ACTIVE; |
1235 | return ERR_PTR(error); | ||
1236 | } | ||
1237 | s->s_flags |= SB_ACTIVE; | ||
1238 | } else { | 1273 | } else { |
1239 | do_remount_sb(s, flags, data, 0); | 1274 | error = reconfigure_single(s, flags, data); |
1275 | } | ||
1276 | if (unlikely(error)) { | ||
1277 | deactivate_locked_super(s); | ||
1278 | return ERR_PTR(error); | ||
1240 | } | 1279 | } |
1241 | return dget(s->s_root); | 1280 | return dget(s->s_root); |
1242 | } | 1281 | } |