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 */ |
