* [PATCH 0/1] man2/mount.2: expand and clarify docs for MS_REMOUNT | MS_BIND
@ 2025-08-22 11:43 Askar Safin
2025-08-22 11:43 ` [PATCH 1/1] " Askar Safin
0 siblings, 1 reply; 5+ messages in thread
From: Askar Safin @ 2025-08-22 11:43 UTC (permalink / raw)
To: Alejandro Colomar
Cc: Aleksa Sarai, Alexander Viro, linux-api, linux-fsdevel,
David Howells, Christian Brauner, linux-man
My edit is based on experiments and reading Linux code
You will find C code I used for experiments below
Askar Safin (1):
man2/mount.2: expand and clarify docs for MS_REMOUNT | MS_BIND
man/man2/mount.2 | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
--
2.47.2
// You need to be root in initial user namespace
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sched.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#include <sys/sysmacros.h>
#include <linux/openat2.h>
#define MY_ASSERT(cond) do { \
if (!(cond)) { \
fprintf (stderr, "%d: %s: assertion failed\n", __LINE__, #cond); \
exit (1); \
} \
} while (0)
int
main (void)
{
// Init
{
MY_ASSERT (chdir ("/") == 0);
MY_ASSERT (unshare (CLONE_NEWNS) == 0);
MY_ASSERT (mount (NULL, "/", NULL, MS_PRIVATE | MS_REC, NULL) == 0);
MY_ASSERT (mount (NULL, "/tmp", "tmpfs", 0, NULL) == 0);
}
MY_ASSERT (mkdir ("/tmp/a", 0777) == 0);
MY_ASSERT (mkdir ("/tmp/b", 0777) == 0);
// MS_REMOUNT sets options for superblock
{
MY_ASSERT (mount (NULL, "/tmp/a", "tmpfs", 0, NULL) == 0);
MY_ASSERT (mount ("/tmp/a", "/tmp/b", NULL, MS_BIND, NULL) == 0);
MY_ASSERT (mount (NULL, "/tmp/a", NULL, MS_REMOUNT | MS_RDONLY, NULL) == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == -1);
MY_ASSERT (errno == EROFS);
MY_ASSERT (mkdir ("/tmp/b/c", 0777) == -1);
MY_ASSERT (errno == EROFS);
MY_ASSERT (umount ("/tmp/a") == 0);
MY_ASSERT (umount ("/tmp/b") == 0);
}
// MS_REMOUNT | MS_BIND sets options for vfsmount
{
MY_ASSERT (mount (NULL, "/tmp/a", "tmpfs", 0, NULL) == 0);
MY_ASSERT (mount ("/tmp/a", "/tmp/b", NULL, MS_BIND, NULL) == 0);
MY_ASSERT (mount (NULL, "/tmp/a", NULL, MS_REMOUNT | MS_BIND | MS_RDONLY, NULL) == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == -1);
MY_ASSERT (errno == EROFS);
MY_ASSERT (mkdir ("/tmp/b/c", 0777) == 0);
MY_ASSERT (rmdir ("/tmp/b/c") == 0);
MY_ASSERT (umount ("/tmp/a") == 0);
MY_ASSERT (umount ("/tmp/b") == 0);
}
// fspick sets options for superblock
{
MY_ASSERT (mount (NULL, "/tmp/a", "tmpfs", 0, NULL) == 0);
MY_ASSERT (mount ("/tmp/a", "/tmp/b", NULL, MS_BIND, NULL) == 0);
{
int fsfd = fspick (AT_FDCWD, "/tmp/a", 0);
MY_ASSERT (fsfd >= 0);
MY_ASSERT (fsconfig (fsfd, FSCONFIG_SET_FLAG, "ro", NULL, 0) == 0);
MY_ASSERT (fsconfig (fsfd, FSCONFIG_CMD_RECONFIGURE, NULL, NULL, 0) == 0);
MY_ASSERT (close (fsfd) == 0);
}
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == -1);
MY_ASSERT (errno == EROFS);
MY_ASSERT (mkdir ("/tmp/b/c", 0777) == -1);
MY_ASSERT (errno == EROFS);
MY_ASSERT (umount ("/tmp/a") == 0);
MY_ASSERT (umount ("/tmp/b") == 0);
}
// mount_setattr sets options for vfsmount
{
MY_ASSERT (mount (NULL, "/tmp/a", "tmpfs", 0, NULL) == 0);
MY_ASSERT (mount ("/tmp/a", "/tmp/b", NULL, MS_BIND, NULL) == 0);
{
struct mount_attr attr;
memset (&attr, 0, sizeof attr);
attr.attr_set = MOUNT_ATTR_RDONLY;
MY_ASSERT (mount_setattr (AT_FDCWD, "/tmp/a", 0, &attr, sizeof attr) == 0);
}
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == -1);
MY_ASSERT (errno == EROFS);
MY_ASSERT (mkdir ("/tmp/b/c", 0777) == 0);
MY_ASSERT (rmdir ("/tmp/b/c") == 0);
MY_ASSERT (umount ("/tmp/a") == 0);
MY_ASSERT (umount ("/tmp/b") == 0);
}
// "ro" as a string works for MS_REMOUNT
{
MY_ASSERT (mount (NULL, "/tmp/a", "tmpfs", 0, NULL) == 0);
MY_ASSERT (mount ("/tmp/a", "/tmp/b", NULL, MS_BIND, NULL) == 0);
MY_ASSERT (mount (NULL, "/tmp/a", NULL, MS_REMOUNT, "ro") == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == -1);
MY_ASSERT (errno == EROFS);
MY_ASSERT (mkdir ("/tmp/b/c", 0777) == -1);
MY_ASSERT (errno == EROFS);
MY_ASSERT (umount ("/tmp/a") == 0);
MY_ASSERT (umount ("/tmp/b") == 0);
}
// "ro" as a string doesn't work for MS_REMOUNT | MS_BIND
// Option string is ignored
{
MY_ASSERT (mount (NULL, "/tmp/a", "tmpfs", 0, NULL) == 0);
MY_ASSERT (mount ("/tmp/a", "/tmp/b", NULL, MS_BIND, NULL) == 0);
MY_ASSERT (mount (NULL, "/tmp/a", NULL, MS_REMOUNT | MS_BIND, "ro") == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == 0);
MY_ASSERT (rmdir ("/tmp/a/c") == 0);
MY_ASSERT (mkdir ("/tmp/b/c", 0777) == 0);
MY_ASSERT (rmdir ("/tmp/b/c") == 0);
MY_ASSERT (umount ("/tmp/a") == 0);
MY_ASSERT (umount ("/tmp/b") == 0);
}
// Removing MS_RDONLY makes mount writable again (in case of MS_REMOUNT | MS_BIND)
// Same for other options (not tested, but I did read code)
{
MY_ASSERT (mount (NULL, "/tmp/a", "tmpfs", 0, NULL) == 0);
MY_ASSERT (mount (NULL, "/tmp/a", NULL, MS_REMOUNT | MS_BIND | MS_RDONLY, NULL) == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == -1);
MY_ASSERT (errno == EROFS);
MY_ASSERT (mount (NULL, "/tmp/a", NULL, MS_REMOUNT | MS_BIND, NULL) == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == 0);
MY_ASSERT (umount ("/tmp/a") == 0);
}
// Removing "ro" from option string makes mount writable again (in case of MS_REMOUNT)
// I. e. mount(2) works exactly as documented
// This works even if option string is NULL, i. e. NULL works as default option string
{
typedef const char *c_string;
c_string opts[3] = {NULL, "", "rw"};
for (int i = 0; i != 3; ++i)
{
for (int j = 0; j != 3; ++j)
{
MY_ASSERT (mount (NULL, "/tmp/a", "tmpfs", 0, opts[i]) == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == 0);
MY_ASSERT (rmdir ("/tmp/a/c") == 0);
MY_ASSERT (mount (NULL, "/tmp/a", NULL, MS_REMOUNT, "ro") == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == -1);
MY_ASSERT (errno == EROFS);
MY_ASSERT (mount (NULL, "/tmp/a", NULL, MS_REMOUNT, opts[j]) == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == 0);
MY_ASSERT (umount ("/tmp/a") == 0);
}
}
}
// Removing MS_RDONLY makes mount writable again (in case of MS_REMOUNT)
// I. e. mount(2) works exactly as documented
{
MY_ASSERT (mount (NULL, "/tmp/a", "tmpfs", 0, NULL) == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == 0);
MY_ASSERT (rmdir ("/tmp/a/c") == 0);
MY_ASSERT (mount (NULL, "/tmp/a", NULL, MS_REMOUNT | MS_RDONLY, NULL) == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == -1);
MY_ASSERT (errno == EROFS);
MY_ASSERT (mount (NULL, "/tmp/a", NULL, MS_REMOUNT, NULL) == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == 0);
MY_ASSERT (rmdir ("/tmp/a/c") == 0);
MY_ASSERT (umount ("/tmp/a") == 0);
}
// Setting MS_RDONLY (without other flags) removes all other flags, such as MS_NODEV (in case of MS_REMOUNT | MS_BIND)
{
MY_ASSERT (mount (NULL, "/tmp/a", "tmpfs", 0, NULL) == 0);
MY_ASSERT (mknod ("/tmp/a/mynull", S_IFCHR | 0666, makedev (1, 3)) == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == 0);
MY_ASSERT (rmdir ("/tmp/a/c") == 0);
{
int fd = open ("/tmp/a/mynull", O_WRONLY);
MY_ASSERT (fd >= 0);
MY_ASSERT (write (fd, "a", 1) == 1);
MY_ASSERT (close (fd) == 0);
}
MY_ASSERT (mount (NULL, "/tmp/a", NULL, MS_REMOUNT | MS_BIND | MS_NODEV, NULL) == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == 0);
MY_ASSERT (rmdir ("/tmp/a/c") == 0);
MY_ASSERT (open ("/tmp/a/mynull", O_WRONLY) == -1);
MY_ASSERT (mount (NULL, "/tmp/a", NULL, MS_REMOUNT | MS_BIND | MS_RDONLY, NULL) == 0);
MY_ASSERT (mkdir ("/tmp/a/c", 0777) == -1);
{
int fd = open ("/tmp/a/mynull", O_WRONLY);
MY_ASSERT (fd >= 0);
MY_ASSERT (write (fd, "a", 1) == 1);
MY_ASSERT (close (fd) == 0);
}
MY_ASSERT (umount ("/tmp/a") == 0);
}
printf ("All tests passed\n");
exit (0);
}
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/1] man2/mount.2: expand and clarify docs for MS_REMOUNT | MS_BIND
2025-08-22 11:43 [PATCH 0/1] man2/mount.2: expand and clarify docs for MS_REMOUNT | MS_BIND Askar Safin
@ 2025-08-22 11:43 ` Askar Safin
2025-08-22 12:49 ` Alejandro Colomar
2025-08-22 13:06 ` Aleksa Sarai
0 siblings, 2 replies; 5+ messages in thread
From: Askar Safin @ 2025-08-22 11:43 UTC (permalink / raw)
To: Alejandro Colomar
Cc: Aleksa Sarai, Alexander Viro, linux-api, linux-fsdevel,
David Howells, Christian Brauner, linux-man
My edit is based on experiments and reading Linux code
Signed-off-by: Askar Safin <safinaskar@zohomail.com>
---
man/man2/mount.2 | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/man/man2/mount.2 b/man/man2/mount.2
index 5d83231f9..909b82e88 100644
--- a/man/man2/mount.2
+++ b/man/man2/mount.2
@@ -405,7 +405,19 @@ flag can be used with
to modify only the per-mount-point flags.
.\" See https://lwn.net/Articles/281157/
This is particularly useful for setting or clearing the "read-only"
-flag on a mount without changing the underlying filesystem.
+flag on a mount without changing flags of the underlying filesystem.
+The
+.I data
+argument is ignored if
+.B MS_REMOUNT
+and
+.B MS_BIND
+are specified.
+The
+.I mountflags
+should specify existing per-mount-point flags,
+except for those parameters
+that are deliberately changed.
Specifying
.I mountflags
as:
@@ -416,8 +428,11 @@ MS_REMOUNT | MS_BIND | MS_RDONLY
.EE
.in
.P
-will make access through this mountpoint read-only, without affecting
-other mounts.
+will make access through this mountpoint read-only
+(and clear all other per-mount-point flags),
+without affecting
+other mounts
+of this filesystem.
.\"
.SS Creating a bind mount
If
--
2.47.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/1] man2/mount.2: expand and clarify docs for MS_REMOUNT | MS_BIND
2025-08-22 11:43 ` [PATCH 1/1] " Askar Safin
@ 2025-08-22 12:49 ` Alejandro Colomar
2025-08-22 13:06 ` Aleksa Sarai
1 sibling, 0 replies; 5+ messages in thread
From: Alejandro Colomar @ 2025-08-22 12:49 UTC (permalink / raw)
To: Askar Safin
Cc: Aleksa Sarai, Alexander Viro, linux-api, linux-fsdevel,
David Howells, Christian Brauner, linux-man
[-- Attachment #1: Type: text/plain, Size: 1750 bytes --]
Hi Askar,
On Fri, Aug 22, 2025 at 11:43:15AM +0000, Askar Safin wrote:
> My edit is based on experiments and reading Linux code
>
> Signed-off-by: Askar Safin <safinaskar@zohomail.com>
You could add Cc: tags there for people you CC'd in the patch.
(For next time.)
I'll wait before applying the patch, to allow anyone to review it, in
case they want to comment.
Have a lovely day!
Alex
> ---
> man/man2/mount.2 | 21 ++++++++++++++++++---
> 1 file changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/man/man2/mount.2 b/man/man2/mount.2
> index 5d83231f9..909b82e88 100644
> --- a/man/man2/mount.2
> +++ b/man/man2/mount.2
> @@ -405,7 +405,19 @@ flag can be used with
> to modify only the per-mount-point flags.
> .\" See https://lwn.net/Articles/281157/
> This is particularly useful for setting or clearing the "read-only"
> -flag on a mount without changing the underlying filesystem.
> +flag on a mount without changing flags of the underlying filesystem.
> +The
> +.I data
> +argument is ignored if
> +.B MS_REMOUNT
> +and
> +.B MS_BIND
> +are specified.
> +The
> +.I mountflags
> +should specify existing per-mount-point flags,
> +except for those parameters
> +that are deliberately changed.
> Specifying
> .I mountflags
> as:
> @@ -416,8 +428,11 @@ MS_REMOUNT | MS_BIND | MS_RDONLY
> .EE
> .in
> .P
> -will make access through this mountpoint read-only, without affecting
> -other mounts.
> +will make access through this mountpoint read-only
> +(and clear all other per-mount-point flags),
> +without affecting
> +other mounts
> +of this filesystem.
> .\"
> .SS Creating a bind mount
> If
> --
> 2.47.2
>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/1] man2/mount.2: expand and clarify docs for MS_REMOUNT | MS_BIND
2025-08-22 11:43 ` [PATCH 1/1] " Askar Safin
2025-08-22 12:49 ` Alejandro Colomar
@ 2025-08-22 13:06 ` Aleksa Sarai
2025-08-25 16:12 ` Askar Safin
1 sibling, 1 reply; 5+ messages in thread
From: Aleksa Sarai @ 2025-08-22 13:06 UTC (permalink / raw)
To: Askar Safin
Cc: Alejandro Colomar, Alexander Viro, linux-api, linux-fsdevel,
David Howells, Christian Brauner, linux-man
[-- Attachment #1: Type: text/plain, Size: 2925 bytes --]
On 2025-08-22, Askar Safin <safinaskar@zohomail.com> wrote:
> My edit is based on experiments and reading Linux code
>
> Signed-off-by: Askar Safin <safinaskar@zohomail.com>
> ---
> man/man2/mount.2 | 21 ++++++++++++++++++---
> 1 file changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/man/man2/mount.2 b/man/man2/mount.2
> index 5d83231f9..909b82e88 100644
> --- a/man/man2/mount.2
> +++ b/man/man2/mount.2
> @@ -405,7 +405,19 @@ flag can be used with
> to modify only the per-mount-point flags.
> .\" See https://lwn.net/Articles/281157/
> This is particularly useful for setting or clearing the "read-only"
> -flag on a mount without changing the underlying filesystem.
> +flag on a mount without changing flags of the underlying filesystem.
For obvious reasons, I would prefer the term "filesystem parameters"
here but mount(2) is kind of loose with its terminology...
> +The
> +.I data
> +argument is ignored if
> +.B MS_REMOUNT
> +and
> +.B MS_BIND
> +are specified.
> +The
> +.I mountflags
> +should specify existing per-mount-point flags,
> +except for those parameters
> +that are deliberately changed.
I would phrase this more like a note to make the advice a bit clearer:
Note that the mountpoint will
have its existing per-mount-point flags
cleared and replaced with those in
.I mountflags
when
.B MS_REMOUNT
and
.B MS_BIND
are specified.
This means that if
you wish to preserve
any existing per-mount-point flags
(which can be retrieved using
.BR statfs (2)),
you need to include them in
.IR mountflags ,
along with the per-mount-point flags you wish to set
(or with the flags you wish to clear missing).
(Still a bit too wordy, there's probably a nicer way of writing it...)
It might also be a good idea to reference locked mount flags (which are
explained in more detail in mount_namespaces(7)) since they are very
relevant to the text you're adding about MS_REMOUNT|MS_BIND.
The current docs only mention locked mounts once and the description is
kind of insufficient (it implies that only MS_REMOUNT affects this, and
that it's related to the mount being locked -- neither is really true).
When dealing with a mount with locked flags, remembering to include
existing mount attributes is very important.
> Specifying
> .I mountflags
> as:
> @@ -416,8 +428,11 @@ MS_REMOUNT | MS_BIND | MS_RDONLY
> .EE
> .in
> .P
> -will make access through this mountpoint read-only, without affecting
> -other mounts.
> +will make access through this mountpoint read-only
> +(and clear all other per-mount-point flags),
(clearing all other per-mount-point flags)
> +without affecting
> +other mounts
> +of this filesystem.
> .\"
> .SS Creating a bind mount
> If
--
Aleksa Sarai
Senior Software Engineer (Containers)
SUSE Linux GmbH
https://www.cyphar.com/
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 265 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/1] man2/mount.2: expand and clarify docs for MS_REMOUNT | MS_BIND
2025-08-22 13:06 ` Aleksa Sarai
@ 2025-08-25 16:12 ` Askar Safin
0 siblings, 0 replies; 5+ messages in thread
From: Askar Safin @ 2025-08-25 16:12 UTC (permalink / raw)
To: Aleksa Sarai
Cc: Alejandro Colomar, Alexander Viro, linux-api, linux-fsdevel,
David Howells, Christian Brauner, linux-man
---- On Fri, 22 Aug 2025 17:06:00 +0400 Aleksa Sarai <cyphar@cyphar.com> wrote ---
> > +The
> > +.I mountflags
> > +should specify existing per-mount-point flags,
> > +except for those parameters
> > +that are deliberately changed.
>
> I would phrase this more like a note to make the advice a bit clearer:
I merely copied here text used for normal remounting (i. e. MS_REMOUNT without MS_BIND).
But okay, I changed anyway.
> (which can be retrieved using
> .BR statfs (2)),
I don't like reference to statfs here.
statfs returns both superblock and per-mount
flags. And you cannot know which is which. See
https://elixir.bootlin.com/linux/v6.17-rc2/source/fs/statfs.c#L51
.
So, I removed statfs reference and kept everything else.
> The current docs only mention locked mounts once and the description is
> kind of insufficient (it implies that only MS_REMOUNT affects this, and
I don't know how locked mounts work. So, if you have something to
add, then you can send separate patch.
I addressed all your points except for mentioned above.
--
Askar Safin
https://types.pl/@safinaskar
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-08-25 16:12 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-22 11:43 [PATCH 0/1] man2/mount.2: expand and clarify docs for MS_REMOUNT | MS_BIND Askar Safin
2025-08-22 11:43 ` [PATCH 1/1] " Askar Safin
2025-08-22 12:49 ` Alejandro Colomar
2025-08-22 13:06 ` Aleksa Sarai
2025-08-25 16:12 ` Askar Safin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).