diff options
-rw-r--r-- | fs/namespace.c | 50 | ||||
-rw-r--r-- | include/linux/mount.h | 1 |
2 files changed, 44 insertions, 7 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index e3ce18d91aad..678f7ce060f2 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -105,7 +105,11 @@ struct vfsmount *alloc_vfsmnt(const char *name) | |||
105 | */ | 105 | */ |
106 | int __mnt_is_readonly(struct vfsmount *mnt) | 106 | int __mnt_is_readonly(struct vfsmount *mnt) |
107 | { | 107 | { |
108 | return (mnt->mnt_sb->s_flags & MS_RDONLY); | 108 | if (mnt->mnt_flags & MNT_READONLY) |
109 | return 1; | ||
110 | if (mnt->mnt_sb->s_flags & MS_RDONLY) | ||
111 | return 1; | ||
112 | return 0; | ||
109 | } | 113 | } |
110 | EXPORT_SYMBOL_GPL(__mnt_is_readonly); | 114 | EXPORT_SYMBOL_GPL(__mnt_is_readonly); |
111 | 115 | ||
@@ -305,7 +309,7 @@ void mnt_drop_write(struct vfsmount *mnt) | |||
305 | } | 309 | } |
306 | EXPORT_SYMBOL_GPL(mnt_drop_write); | 310 | EXPORT_SYMBOL_GPL(mnt_drop_write); |
307 | 311 | ||
308 | int mnt_make_readonly(struct vfsmount *mnt) | 312 | static int mnt_make_readonly(struct vfsmount *mnt) |
309 | { | 313 | { |
310 | int ret = 0; | 314 | int ret = 0; |
311 | 315 | ||
@@ -318,15 +322,25 @@ int mnt_make_readonly(struct vfsmount *mnt) | |||
318 | goto out; | 322 | goto out; |
319 | } | 323 | } |
320 | /* | 324 | /* |
321 | * actually set mount's r/o flag here to make | 325 | * nobody can do a successful mnt_want_write() with all |
322 | * __mnt_is_readonly() true, which keeps anyone | 326 | * of the counts in MNT_DENIED_WRITE and the locks held. |
323 | * from doing a successful mnt_want_write(). | ||
324 | */ | 327 | */ |
328 | spin_lock(&vfsmount_lock); | ||
329 | if (!ret) | ||
330 | mnt->mnt_flags |= MNT_READONLY; | ||
331 | spin_unlock(&vfsmount_lock); | ||
325 | out: | 332 | out: |
326 | unlock_mnt_writers(); | 333 | unlock_mnt_writers(); |
327 | return ret; | 334 | return ret; |
328 | } | 335 | } |
329 | 336 | ||
337 | static void __mnt_unmake_readonly(struct vfsmount *mnt) | ||
338 | { | ||
339 | spin_lock(&vfsmount_lock); | ||
340 | mnt->mnt_flags &= ~MNT_READONLY; | ||
341 | spin_unlock(&vfsmount_lock); | ||
342 | } | ||
343 | |||
330 | int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb) | 344 | int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb) |
331 | { | 345 | { |
332 | mnt->mnt_sb = sb; | 346 | mnt->mnt_sb = sb; |
@@ -693,7 +707,7 @@ static int show_vfsmnt(struct seq_file *m, void *v) | |||
693 | seq_putc(m, '.'); | 707 | seq_putc(m, '.'); |
694 | mangle(m, mnt->mnt_sb->s_subtype); | 708 | mangle(m, mnt->mnt_sb->s_subtype); |
695 | } | 709 | } |
696 | seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw"); | 710 | seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); |
697 | for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { | 711 | for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { |
698 | if (mnt->mnt_sb->s_flags & fs_infop->flag) | 712 | if (mnt->mnt_sb->s_flags & fs_infop->flag) |
699 | seq_puts(m, fs_infop->str); | 713 | seq_puts(m, fs_infop->str); |
@@ -1295,6 +1309,23 @@ out: | |||
1295 | return err; | 1309 | return err; |
1296 | } | 1310 | } |
1297 | 1311 | ||
1312 | static int change_mount_flags(struct vfsmount *mnt, int ms_flags) | ||
1313 | { | ||
1314 | int error = 0; | ||
1315 | int readonly_request = 0; | ||
1316 | |||
1317 | if (ms_flags & MS_RDONLY) | ||
1318 | readonly_request = 1; | ||
1319 | if (readonly_request == __mnt_is_readonly(mnt)) | ||
1320 | return 0; | ||
1321 | |||
1322 | if (readonly_request) | ||
1323 | error = mnt_make_readonly(mnt); | ||
1324 | else | ||
1325 | __mnt_unmake_readonly(mnt); | ||
1326 | return error; | ||
1327 | } | ||
1328 | |||
1298 | /* | 1329 | /* |
1299 | * change filesystem flags. dir should be a physical root of filesystem. | 1330 | * change filesystem flags. dir should be a physical root of filesystem. |
1300 | * If you've mounted a non-root directory somewhere and want to do remount | 1331 | * If you've mounted a non-root directory somewhere and want to do remount |
@@ -1317,7 +1348,10 @@ static noinline int do_remount(struct nameidata *nd, int flags, int mnt_flags, | |||
1317 | return -EINVAL; | 1348 | return -EINVAL; |
1318 | 1349 | ||
1319 | down_write(&sb->s_umount); | 1350 | down_write(&sb->s_umount); |
1320 | err = do_remount_sb(sb, flags, data, 0); | 1351 | if (flags & MS_BIND) |
1352 | err = change_mount_flags(nd->path.mnt, flags); | ||
1353 | else | ||
1354 | err = do_remount_sb(sb, flags, data, 0); | ||
1321 | if (!err) | 1355 | if (!err) |
1322 | nd->path.mnt->mnt_flags = mnt_flags; | 1356 | nd->path.mnt->mnt_flags = mnt_flags; |
1323 | up_write(&sb->s_umount); | 1357 | up_write(&sb->s_umount); |
@@ -1701,6 +1735,8 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, | |||
1701 | mnt_flags |= MNT_NODIRATIME; | 1735 | mnt_flags |= MNT_NODIRATIME; |
1702 | if (flags & MS_RELATIME) | 1736 | if (flags & MS_RELATIME) |
1703 | mnt_flags |= MNT_RELATIME; | 1737 | mnt_flags |= MNT_RELATIME; |
1738 | if (flags & MS_RDONLY) | ||
1739 | mnt_flags |= MNT_READONLY; | ||
1704 | 1740 | ||
1705 | flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | | 1741 | flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | |
1706 | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT); | 1742 | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT); |
diff --git a/include/linux/mount.h b/include/linux/mount.h index 8c8e94369ac8..d6600e3f7e45 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h | |||
@@ -29,6 +29,7 @@ struct mnt_namespace; | |||
29 | #define MNT_NOATIME 0x08 | 29 | #define MNT_NOATIME 0x08 |
30 | #define MNT_NODIRATIME 0x10 | 30 | #define MNT_NODIRATIME 0x10 |
31 | #define MNT_RELATIME 0x20 | 31 | #define MNT_RELATIME 0x20 |
32 | #define MNT_READONLY 0x40 /* does the user want this to be r/o? */ | ||
32 | 33 | ||
33 | #define MNT_SHRINKABLE 0x100 | 34 | #define MNT_SHRINKABLE 0x100 |
34 | #define MNT_IMBALANCED_WRITE_COUNT 0x200 /* just for debugging */ | 35 | #define MNT_IMBALANCED_WRITE_COUNT 0x200 /* just for debugging */ |