<feed xmlns='http://www.w3.org/2005/Atom'>
<title>linux.git/fs/namespace.c, branch v6.12</title>
<subtitle>Linux kernel source tree</subtitle>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/'/>
<entry>
<title>fs: don't try and remove empty rbtree node</title>
<updated>2024-10-17T13:33:43+00:00</updated>
<author>
<name>Christian Brauner</name>
<email>brauner@kernel.org</email>
</author>
<published>2024-10-16T17:49:48+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=229fd15908fe1f99b1de4cde3326e62d1e892611'/>
<id>229fd15908fe1f99b1de4cde3326e62d1e892611</id>
<content type='text'>
When copying a namespace we won't have added the new copy into the
namespace rbtree until after the copy succeeded. Calling free_mnt_ns()
will try to remove the copy from the rbtree which is invalid. Simply
free the namespace skeleton directly.

Link: https://lore.kernel.org/r/20241016-adapter-seilwinde-83c508a7bde1@brauner
Fixes: 1901c92497bd ("fs: keep an index of current mount namespaces")
Tested-by: Brad Spengler &lt;spender@grsecurity.net&gt;
Cc: stable@vger.kernel.org # v6.11+
Reported-by: Brad Spengler &lt;spender@grsecurity.net&gt;
Suggested-by: Brad Spengler &lt;spender@grsecurity.net&gt;
Signed-off-by: Christian Brauner &lt;brauner@kernel.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When copying a namespace we won't have added the new copy into the
namespace rbtree until after the copy succeeded. Calling free_mnt_ns()
will try to remove the copy from the rbtree which is invalid. Simply
free the namespace skeleton directly.

Link: https://lore.kernel.org/r/20241016-adapter-seilwinde-83c508a7bde1@brauner
Fixes: 1901c92497bd ("fs: keep an index of current mount namespaces")
Tested-by: Brad Spengler &lt;spender@grsecurity.net&gt;
Cc: stable@vger.kernel.org # v6.11+
Reported-by: Brad Spengler &lt;spender@grsecurity.net&gt;
Suggested-by: Brad Spengler &lt;spender@grsecurity.net&gt;
Signed-off-by: Christian Brauner &lt;brauner@kernel.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Merge tag 'fuse-update-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse</title>
<updated>2024-09-24T22:29:42+00:00</updated>
<author>
<name>Linus Torvalds</name>
<email>torvalds@linux-foundation.org</email>
</author>
<published>2024-09-24T22:29:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=f7fccaa772718f6d2e798dece4a5210fe4c406ec'/>
<id>f7fccaa772718f6d2e798dece4a5210fe4c406ec</id>
<content type='text'>
Pull fuse updates from Miklos Szeredi:

 - Add support for idmapped fuse mounts (Alexander Mikhalitsyn)

 - Add optimization when checking for writeback (yangyun)

 - Add tracepoints (Josef Bacik)

 - Clean up writeback code (Joanne Koong)

 - Clean up request queuing (me)

 - Misc fixes

* tag 'fuse-update-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: (32 commits)
  fuse: use exclusive lock when FUSE_I_CACHE_IO_MODE is set
  fuse: clear FR_PENDING if abort is detected when sending request
  fs/fuse: convert to use invalid_mnt_idmap
  fs/mnt_idmapping: introduce an invalid_mnt_idmap
  fs/fuse: introduce and use fuse_simple_idmap_request() helper
  fs/fuse: fix null-ptr-deref when checking SB_I_NOIDMAP flag
  fuse: allow O_PATH fd for FUSE_DEV_IOC_BACKING_OPEN
  virtio_fs: allow idmapped mounts
  fuse: allow idmapped mounts
  fuse: warn if fuse_access is called when idmapped mounts are allowed
  fuse: handle idmappings properly in -&gt;write_iter()
  fuse: support idmapped -&gt;rename op
  fuse: support idmapped -&gt;set_acl
  fuse: drop idmap argument from __fuse_get_acl
  fuse: support idmapped -&gt;setattr op
  fuse: support idmapped -&gt;permission inode op
  fuse: support idmapped getattr inode op
  fuse: support idmap for mkdir/mknod/symlink/create/tmpfile
  fuse: support idmapped FUSE_EXT_GROUPS
  fuse: add an idmap argument to fuse_simple_request
  ...
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Pull fuse updates from Miklos Szeredi:

 - Add support for idmapped fuse mounts (Alexander Mikhalitsyn)

 - Add optimization when checking for writeback (yangyun)

 - Add tracepoints (Josef Bacik)

 - Clean up writeback code (Joanne Koong)

 - Clean up request queuing (me)

 - Misc fixes

* tag 'fuse-update-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: (32 commits)
  fuse: use exclusive lock when FUSE_I_CACHE_IO_MODE is set
  fuse: clear FR_PENDING if abort is detected when sending request
  fs/fuse: convert to use invalid_mnt_idmap
  fs/mnt_idmapping: introduce an invalid_mnt_idmap
  fs/fuse: introduce and use fuse_simple_idmap_request() helper
  fs/fuse: fix null-ptr-deref when checking SB_I_NOIDMAP flag
  fuse: allow O_PATH fd for FUSE_DEV_IOC_BACKING_OPEN
  virtio_fs: allow idmapped mounts
  fuse: allow idmapped mounts
  fuse: warn if fuse_access is called when idmapped mounts are allowed
  fuse: handle idmappings properly in -&gt;write_iter()
  fuse: support idmapped -&gt;rename op
  fuse: support idmapped -&gt;set_acl
  fuse: drop idmap argument from __fuse_get_acl
  fuse: support idmapped -&gt;setattr op
  fuse: support idmapped -&gt;permission inode op
  fuse: support idmapped getattr inode op
  fuse: support idmap for mkdir/mknod/symlink/create/tmpfile
  fuse: support idmapped FUSE_EXT_GROUPS
  fuse: add an idmap argument to fuse_simple_request
  ...
</pre>
</div>
</content>
</entry>
<entry>
<title>Merge tag 'pull-stable-struct_fd' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs</title>
<updated>2024-09-23T16:35:36+00:00</updated>
<author>
<name>Linus Torvalds</name>
<email>torvalds@linux-foundation.org</email>
</author>
<published>2024-09-23T16:35:36+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=f8ffbc365f703d74ecca8ca787318d05bbee2bf7'/>
<id>f8ffbc365f703d74ecca8ca787318d05bbee2bf7</id>
<content type='text'>
Pull 'struct fd' updates from Al Viro:
 "Just the 'struct fd' layout change, with conversion to accessor
  helpers"

* tag 'pull-stable-struct_fd' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  add struct fd constructors, get rid of __to_fd()
  struct fd: representation change
  introduce fd_file(), convert all accessors to it.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Pull 'struct fd' updates from Al Viro:
 "Just the 'struct fd' layout change, with conversion to accessor
  helpers"

* tag 'pull-stable-struct_fd' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  add struct fd constructors, get rid of __to_fd()
  struct fd: representation change
  introduce fd_file(), convert all accessors to it.
</pre>
</div>
</content>
</entry>
<entry>
<title>Merge tag 'vfs-6.12.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs</title>
<updated>2024-09-16T09:15:26+00:00</updated>
<author>
<name>Linus Torvalds</name>
<email>torvalds@linux-foundation.org</email>
</author>
<published>2024-09-16T09:15:26+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=9020d0d844ad58a051f90b1e5b82ba34123925b9'/>
<id>9020d0d844ad58a051f90b1e5b82ba34123925b9</id>
<content type='text'>
Pull vfs mount updates from Christian Brauner:
 "Recently, we added the ability to list mounts in other mount
  namespaces and the ability to retrieve namespace file descriptors
  without having to go through procfs by deriving them from pidfds.

  This extends nsfs in two ways:

   (1) Add the ability to retrieve information about a mount namespace
       via NS_MNT_GET_INFO.

       This will return the mount namespace id and the number of mounts
       currently in the mount namespace. The number of mounts can be
       used to size the buffer that needs to be used for listmount() and
       is in general useful without having to actually iterate through
       all the mounts.

      The structure is extensible.

   (2) Add the ability to iterate through all mount namespaces over
       which the caller holds privilege returning the file descriptor
       for the next or previous mount namespace.

       To retrieve a mount namespace the caller must be privileged wrt
       to it's owning user namespace. This means that PID 1 on the host
       can list all mounts in all mount namespaces or that a container
       can list all mounts of its nested containers.

       Optionally pass a structure for NS_MNT_GET_INFO with
       NS_MNT_GET_{PREV,NEXT} to retrieve information about the mount
       namespace in one go.

  (1) and (2) can be implemented for other namespace types easily.

  Together with recent api additions this means one can iterate through
  all mounts in all mount namespaces without ever touching procfs.

  The commit message in 49224a345c48 ('Merge patch series "nsfs: iterate
  through mount namespaces"') contains example code how to do this"

* tag 'vfs-6.12.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  nsfs: iterate through mount namespaces
  file: add fput() cleanup helper
  fs: add put_mnt_ns() cleanup helper
  fs: allow mount namespace fd
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Pull vfs mount updates from Christian Brauner:
 "Recently, we added the ability to list mounts in other mount
  namespaces and the ability to retrieve namespace file descriptors
  without having to go through procfs by deriving them from pidfds.

  This extends nsfs in two ways:

   (1) Add the ability to retrieve information about a mount namespace
       via NS_MNT_GET_INFO.

       This will return the mount namespace id and the number of mounts
       currently in the mount namespace. The number of mounts can be
       used to size the buffer that needs to be used for listmount() and
       is in general useful without having to actually iterate through
       all the mounts.

      The structure is extensible.

   (2) Add the ability to iterate through all mount namespaces over
       which the caller holds privilege returning the file descriptor
       for the next or previous mount namespace.

       To retrieve a mount namespace the caller must be privileged wrt
       to it's owning user namespace. This means that PID 1 on the host
       can list all mounts in all mount namespaces or that a container
       can list all mounts of its nested containers.

       Optionally pass a structure for NS_MNT_GET_INFO with
       NS_MNT_GET_{PREV,NEXT} to retrieve information about the mount
       namespace in one go.

  (1) and (2) can be implemented for other namespace types easily.

  Together with recent api additions this means one can iterate through
  all mounts in all mount namespaces without ever touching procfs.

  The commit message in 49224a345c48 ('Merge patch series "nsfs: iterate
  through mount namespaces"') contains example code how to do this"

* tag 'vfs-6.12.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  nsfs: iterate through mount namespaces
  file: add fput() cleanup helper
  fs: add put_mnt_ns() cleanup helper
  fs: allow mount namespace fd
</pre>
</div>
</content>
</entry>
<entry>
<title>namespace: introduce SB_I_NOIDMAP flag</title>
<updated>2024-09-04T14:47:49+00:00</updated>
<author>
<name>Alexander Mikhalitsyn</name>
<email>aleksandr.mikhalitsyn@canonical.com</email>
</author>
<published>2024-09-03T15:16:12+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=2097154a10c6ee78be8796411e5d0ad81ee06ed6'/>
<id>2097154a10c6ee78be8796411e5d0ad81ee06ed6</id>
<content type='text'>
Right now we determine if filesystem support vfs idmappings or not basing
on the FS_ALLOW_IDMAP flag presence. This "static" way works perfecly well
for local filesystems like ext4, xfs, btrfs, etc. But for network-like
filesystems like fuse, cephfs this approach is not ideal, because sometimes
proper support of vfs idmaps requires some extensions for the on-wire
protocol, which implies that changes have to be made not only in the Linux
kernel code but also in the 3rd party components like libfuse, cephfs MDS
server and so on.

We have seen that issue during our work on cephfs idmapped mounts [1] with
Christian, but right now I'm working on the idmapped mounts support for
fuse/virtiofs and I think that it is a right time for this extension.

[1] 5ccd8530dd7 ("ceph: handle idmapped mounts in create_request_message()")

Suggested-by: Christian Brauner &lt;brauner@kernel.org&gt;
Signed-off-by: Alexander Mikhalitsyn &lt;aleksandr.mikhalitsyn@canonical.com&gt;
Reviewed-by: Christian Brauner &lt;brauner@kernel.org&gt;
Signed-off-by: Miklos Szeredi &lt;mszeredi@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Right now we determine if filesystem support vfs idmappings or not basing
on the FS_ALLOW_IDMAP flag presence. This "static" way works perfecly well
for local filesystems like ext4, xfs, btrfs, etc. But for network-like
filesystems like fuse, cephfs this approach is not ideal, because sometimes
proper support of vfs idmaps requires some extensions for the on-wire
protocol, which implies that changes have to be made not only in the Linux
kernel code but also in the 3rd party components like libfuse, cephfs MDS
server and so on.

We have seen that issue during our work on cephfs idmapped mounts [1] with
Christian, but right now I'm working on the idmapped mounts support for
fuse/virtiofs and I think that it is a right time for this extension.

[1] 5ccd8530dd7 ("ceph: handle idmapped mounts in create_request_message()")

Suggested-by: Christian Brauner &lt;brauner@kernel.org&gt;
Signed-off-by: Alexander Mikhalitsyn &lt;aleksandr.mikhalitsyn@canonical.com&gt;
Reviewed-by: Christian Brauner &lt;brauner@kernel.org&gt;
Signed-off-by: Miklos Szeredi &lt;mszeredi@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fs/namespace.c: Fix typo in comment</title>
<updated>2024-08-30T06:22:33+00:00</updated>
<author>
<name>Yuesong Li</name>
<email>liyuesong@vivo.com</email>
</author>
<published>2024-08-06T03:47:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=c5ae8e5e5a34963513bf973e77dd15da7333054e'/>
<id>c5ae8e5e5a34963513bf973e77dd15da7333054e</id>
<content type='text'>
replace 'permanetly' with 'permanently' in the comment &amp;
replace 'propogated' with 'propagated' in the comment

Signed-off-by: Yuesong Li &lt;liyuesong@vivo.com&gt;
Link: https://lore.kernel.org/r/20240806034710.2807788-1-liyuesong@vivo.com
Signed-off-by: Christian Brauner &lt;brauner@kernel.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
replace 'permanetly' with 'permanently' in the comment &amp;
replace 'propogated' with 'propagated' in the comment

Signed-off-by: Yuesong Li &lt;liyuesong@vivo.com&gt;
Link: https://lore.kernel.org/r/20240806034710.2807788-1-liyuesong@vivo.com
Signed-off-by: Christian Brauner &lt;brauner@kernel.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>mount: handle OOM on mnt_warn_timestamp_expiry</title>
<updated>2024-08-19T11:45:02+00:00</updated>
<author>
<name>Olaf Hering</name>
<email>olaf@aepfle.de</email>
</author>
<published>2024-07-30T08:58:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=4bcda1eaf184e308f07f9c61d3a535f9ce477ce8'/>
<id>4bcda1eaf184e308f07f9c61d3a535f9ce477ce8</id>
<content type='text'>
If no page could be allocated, an error pointer was used as format
string in pr_warn.

Rearrange the code to return early in case of OOM. Also add a check
for the return value of d_path.

Fixes: f8b92ba67c5d ("mount: Add mount warning for impending timestamp expiry")
Signed-off-by: Olaf Hering &lt;olaf@aepfle.de&gt;
Link: https://lore.kernel.org/r/20240730085856.32385-1-olaf@aepfle.de
[brauner: rewrite commit and commit message]
Signed-off-by: Christian Brauner &lt;brauner@kernel.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
If no page could be allocated, an error pointer was used as format
string in pr_warn.

Rearrange the code to return early in case of OOM. Also add a check
for the return value of d_path.

Fixes: f8b92ba67c5d ("mount: Add mount warning for impending timestamp expiry")
Signed-off-by: Olaf Hering &lt;olaf@aepfle.de&gt;
Link: https://lore.kernel.org/r/20240730085856.32385-1-olaf@aepfle.de
[brauner: rewrite commit and commit message]
Signed-off-by: Christian Brauner &lt;brauner@kernel.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>introduce fd_file(), convert all accessors to it.</title>
<updated>2024-08-13T02:00:43+00:00</updated>
<author>
<name>Al Viro</name>
<email>viro@zeniv.linux.org.uk</email>
</author>
<published>2024-05-31T18:12:01+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=1da91ea87aefe2c25b68c9f96947a9271ba6325d'/>
<id>1da91ea87aefe2c25b68c9f96947a9271ba6325d</id>
<content type='text'>
	For any changes of struct fd representation we need to
turn existing accesses to fields into calls of wrappers.
Accesses to struct fd::flags are very few (3 in linux/file.h,
1 in net/socket.c, 3 in fs/overlayfs/file.c and 3 more in
explicit initializers).
	Those can be dealt with in the commit converting to
new layout; accesses to struct fd::file are too many for that.
	This commit converts (almost) all of f.file to
fd_file(f).  It's not entirely mechanical ('file' is used as
a member name more than just in struct fd) and it does not
even attempt to distinguish the uses in pointer context from
those in boolean context; the latter will be eventually turned
into a separate helper (fd_empty()).

	NOTE: mass conversion to fd_empty(), tempting as it
might be, is a bad idea; better do that piecewise in commit
that convert from fdget...() to CLASS(...).

[conflicts in fs/fhandle.c, kernel/bpf/syscall.c, mm/memcontrol.c
caught by git; fs/stat.c one got caught by git grep]
[fs/xattr.c conflict]

Reviewed-by: Christian Brauner &lt;brauner@kernel.org&gt;
Signed-off-by: Al Viro &lt;viro@zeniv.linux.org.uk&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
	For any changes of struct fd representation we need to
turn existing accesses to fields into calls of wrappers.
Accesses to struct fd::flags are very few (3 in linux/file.h,
1 in net/socket.c, 3 in fs/overlayfs/file.c and 3 more in
explicit initializers).
	Those can be dealt with in the commit converting to
new layout; accesses to struct fd::file are too many for that.
	This commit converts (almost) all of f.file to
fd_file(f).  It's not entirely mechanical ('file' is used as
a member name more than just in struct fd) and it does not
even attempt to distinguish the uses in pointer context from
those in boolean context; the latter will be eventually turned
into a separate helper (fd_empty()).

	NOTE: mass conversion to fd_empty(), tempting as it
might be, is a bad idea; better do that piecewise in commit
that convert from fdget...() to CLASS(...).

[conflicts in fs/fhandle.c, kernel/bpf/syscall.c, mm/memcontrol.c
caught by git; fs/stat.c one got caught by git grep]
[fs/xattr.c conflict]

Reviewed-by: Christian Brauner &lt;brauner@kernel.org&gt;
Signed-off-by: Al Viro &lt;viro@zeniv.linux.org.uk&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Merge patch series "nsfs: iterate through mount namespaces"</title>
<updated>2024-08-09T10:47:05+00:00</updated>
<author>
<name>Christian Brauner</name>
<email>brauner@kernel.org</email>
</author>
<published>2024-08-09T10:44:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=49224a345c488a0e176f193a60a2a76e82349e3e'/>
<id>49224a345c488a0e176f193a60a2a76e82349e3e</id>
<content type='text'>
Christian Brauner &lt;brauner@kernel.org&gt; says:

Recently, we added the ability to list mounts in other mount namespaces
and the ability to retrieve namespace file descriptors without having to
go through procfs by deriving them from pidfds.

This extends nsfs in two ways:

(1) Add the ability to retrieve information about a mount namespace via
    NS_MNT_GET_INFO. This will return the mount namespace id and the
    number of mounts currently in the mount namespace. The number of
    mounts can be used to size the buffer that needs to be used for
    listmount() and is in general useful without having to actually
    iterate through all the mounts.

    The structure is extensible.

(2) Add the ability to iterate through all mount namespaces over which
    the caller holds privilege returning the file descriptor for the
    next or previous mount namespace.

    To retrieve a mount namespace the caller must be privileged wrt to
    it's owning user namespace. This means that PID 1 on the host can
    list all mounts in all mount namespaces or that a container can list
    all mounts of its nested containers.

    Optionally pass a structure for NS_MNT_GET_INFO with
    NS_MNT_GET_{PREV,NEXT} to retrieve information about the mount
    namespace in one go.

(1) and (2) can be implemented for other namespace types easily.

Together with recent api additions this means one can iterate through
all mounts in all mount namespaces without ever touching procfs. Here's
a sample program list_all_mounts_everywhere.c:

  // SPDX-License-Identifier: GPL-2.0-or-later

  #define _GNU_SOURCE
  #include &lt;asm/unistd.h&gt;
  #include &lt;assert.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;getopt.h&gt;
  #include &lt;linux/stat.h&gt;
  #include &lt;sched.h&gt;
  #include &lt;stddef.h&gt;
  #include &lt;stdint.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;string.h&gt;
  #include &lt;sys/ioctl.h&gt;
  #include &lt;sys/param.h&gt;
  #include &lt;sys/pidfd.h&gt;
  #include &lt;sys/stat.h&gt;
  #include &lt;sys/statfs.h&gt;

  #define die_errno(format, ...)                                             \
  	do {                                                               \
  		fprintf(stderr, "%m | %s: %d: %s: " format "\n", __FILE__, \
  			__LINE__, __func__, ##__VA_ARGS__);                \
  		exit(EXIT_FAILURE);                                        \
  	} while (0)

  /* Get the id for a mount namespace */
  #define NS_GET_MNTNS_ID		_IO(0xb7, 0x5)
  /* Get next mount namespace. */

  struct mnt_ns_info {
  	__u32 size;
  	__u32 nr_mounts;
  	__u64 mnt_ns_id;
  };

  #define MNT_NS_INFO_SIZE_VER0 16 /* size of first published struct */

  /* Get information about namespace. */
  #define NS_MNT_GET_INFO		_IOR(0xb7, 10, struct mnt_ns_info)
  /* Get next namespace. */
  #define NS_MNT_GET_NEXT		_IOR(0xb7, 11, struct mnt_ns_info)
  /* Get previous namespace. */
  #define NS_MNT_GET_PREV		_IOR(0xb7, 12, struct mnt_ns_info)

  #define PIDFD_GET_MNT_NAMESPACE _IO(0xFF, 3)

  #define STATX_MNT_ID_UNIQUE	0x00004000U	/* Want/got extended stx_mount_id */

  #define __NR_listmount 458
  #define __NR_statmount 457

  /*
   * @mask bits for statmount(2)
   */
  #define STATMOUNT_SB_BASIC		0x00000001U     /* Want/got sb_... */
  #define STATMOUNT_MNT_BASIC		0x00000002U	/* Want/got mnt_... */
  #define STATMOUNT_PROPAGATE_FROM	0x00000004U	/* Want/got propagate_from */
  #define STATMOUNT_MNT_ROOT		0x00000008U	/* Want/got mnt_root  */
  #define STATMOUNT_MNT_POINT		0x00000010U	/* Want/got mnt_point */
  #define STATMOUNT_FS_TYPE		0x00000020U	/* Want/got fs_type */
  #define STATMOUNT_MNT_NS_ID             0x00000040U     /* Want/got mnt_ns_id */
  #define STATMOUNT_MNT_OPTS              0x00000080U     /* Want/got mnt_opts */

  struct statmount {
  	__u32 size;		/* Total size, including strings */
  	__u32 mnt_opts;
  	__u64 mask;		/* What results were written */
  	__u32 sb_dev_major;	/* Device ID */
  	__u32 sb_dev_minor;
  	__u64 sb_magic;		/* ..._SUPER_MAGIC */
  	__u32 sb_flags;		/* SB_{RDONLY,SYNCHRONOUS,DIRSYNC,LAZYTIME} */
  	__u32 fs_type;		/* [str] Filesystem type */
  	__u64 mnt_id;		/* Unique ID of mount */
  	__u64 mnt_parent_id;	/* Unique ID of parent (for root == mnt_id) */
  	__u32 mnt_id_old;	/* Reused IDs used in proc/.../mountinfo */
  	__u32 mnt_parent_id_old;
  	__u64 mnt_attr;		/* MOUNT_ATTR_... */
  	__u64 mnt_propagation;	/* MS_{SHARED,SLAVE,PRIVATE,UNBINDABLE} */
  	__u64 mnt_peer_group;	/* ID of shared peer group */
  	__u64 mnt_master;	/* Mount receives propagation from this ID */
  	__u64 propagate_from;	/* Propagation from in current namespace */
  	__u32 mnt_root;		/* [str] Root of mount relative to root of fs */
  	__u32 mnt_point;	/* [str] Mountpoint relative to current root */
  	__u64 mnt_ns_id;
  	__u64 __spare2[49];
  	char str[];		/* Variable size part containing strings */
  };

  struct mnt_id_req {
  	__u32 size;
  	__u32 spare;
  	__u64 mnt_id;
  	__u64 param;
  	__u64 mnt_ns_id;
  };

  #define MNT_ID_REQ_SIZE_VER1	32 /* sizeof second published struct */

  #define LSMT_ROOT		0xffffffffffffffff	/* root mount */

  static int __statmount(__u64 mnt_id, __u64 mnt_ns_id, __u64 mask,
  		       struct statmount *stmnt, size_t bufsize, unsigned int flags)
  {
  	struct mnt_id_req req = {
  		.size = MNT_ID_REQ_SIZE_VER1,
  		.mnt_id = mnt_id,
  		.param = mask,
  		.mnt_ns_id = mnt_ns_id,
  	};

  	return syscall(__NR_statmount, &amp;req, stmnt, bufsize, flags);
  }

  static struct statmount *sys_statmount(__u64 mnt_id, __u64 mnt_ns_id,
  				       __u64 mask, unsigned int flags)
  {
  	size_t bufsize = 1 &lt;&lt; 15;
  	struct statmount *stmnt = NULL, *tmp = NULL;
  	int ret;

  	for (;;) {
  		tmp = realloc(stmnt, bufsize);
  		if (!tmp)
  			goto out;

  		stmnt = tmp;
  		ret = __statmount(mnt_id, mnt_ns_id, mask, stmnt, bufsize, flags);
  		if (!ret)
  			return stmnt;

  		if (errno != EOVERFLOW)
  			goto out;

  		bufsize &lt;&lt;= 1;
  		if (bufsize &gt;= UINT_MAX / 2)
  			goto out;

  	}

  out:
  	free(stmnt);
  	printf("statmount failed");
  	return NULL;
  }

  static ssize_t sys_listmount(__u64 mnt_id, __u64 last_mnt_id, __u64 mnt_ns_id,
  			     __u64 list[], size_t num, unsigned int flags)
  {
  	struct mnt_id_req req = {
  		.size = MNT_ID_REQ_SIZE_VER1,
  		.mnt_id = mnt_id,
  		.param = last_mnt_id,
  		.mnt_ns_id = mnt_ns_id,
  	};

  	return syscall(__NR_listmount, &amp;req, list, num, flags);
  }

  int main(int argc, char *argv[])
  {
  #define LISTMNT_BUFFER 10
  	__u64 list[LISTMNT_BUFFER], last_mnt_id = 0;
  	int ret, pidfd, fd_mntns;
  	struct mnt_ns_info info = {};

  	pidfd = pidfd_open(getpid(), 0);
  	if (pidfd &lt; 0)
  		die_errno("pidfd_open failed");

  	fd_mntns = ioctl(pidfd, PIDFD_GET_MNT_NAMESPACE, 0);
  	if (fd_mntns &lt; 0)
  		die_errno("ioctl(PIDFD_GET_MNT_NAMESPACE) failed");

  	ret = ioctl(fd_mntns, NS_MNT_GET_INFO, &amp;info);
  	if (ret &lt; 0)
  		die_errno("ioctl(NS_GET_MNTNS_ID) failed");

  	printf("Listing %u mounts for mount namespace %d:%llu\n", info.nr_mounts, fd_mntns, info.mnt_ns_id);
  	for (;;) {
  		ssize_t nr_mounts;
  	next:
  		nr_mounts = sys_listmount(LSMT_ROOT, last_mnt_id, info.mnt_ns_id, list, LISTMNT_BUFFER, 0);
  		if (nr_mounts &lt;= 0) {
  			printf("Finished listing mounts for mount namespace %d:%llu\n\n", fd_mntns, info.mnt_ns_id);
  			ret = ioctl(fd_mntns, NS_MNT_GET_NEXT, 0);
  			if (ret &lt; 0)
  				die_errno("ioctl(NS_MNT_GET_NEXT) failed");
  			close(ret);
  			ret = ioctl(fd_mntns, NS_MNT_GET_NEXT, &amp;info);
  			if (ret &lt; 0) {
  				if (errno == ENOENT) {
  					printf("Finished listing all mount namespaces\n");
  					exit(0);
  				}
  				die_errno("ioctl(NS_MNT_GET_NEXT) failed");
  			}
  			close(fd_mntns);
  			fd_mntns = ret;
  			last_mnt_id = 0;
  			printf("Listing %u mounts for mount namespace %d:%llu\n", info.nr_mounts, fd_mntns, info.mnt_ns_id);
  			goto next;
  		}

  		for (size_t cur = 0; cur &lt; nr_mounts; cur++) {
  			struct statmount *stmnt;

  			last_mnt_id = list[cur];

  			stmnt = sys_statmount(last_mnt_id, info.mnt_ns_id,
  					      STATMOUNT_SB_BASIC |
  					      STATMOUNT_MNT_BASIC |
  					      STATMOUNT_MNT_ROOT |
  					      STATMOUNT_MNT_POINT |
  					      STATMOUNT_MNT_NS_ID |
  					      STATMOUNT_MNT_OPTS |
  					      STATMOUNT_FS_TYPE,
  					  0);
  			if (!stmnt) {
  				printf("Failed to statmount(%llu) in mount namespace(%llu)\n", last_mnt_id, info.mnt_ns_id);
  				continue;
  			}

  			printf("mnt_id(%u/%llu) | mnt_parent_id(%u/%llu): %s @ %s ==&gt; %s with options: %s\n",
  			       stmnt-&gt;mnt_id_old, stmnt-&gt;mnt_id,
  			       stmnt-&gt;mnt_parent_id_old, stmnt-&gt;mnt_parent_id,
  			       stmnt-&gt;str + stmnt-&gt;fs_type,
  			       stmnt-&gt;str + stmnt-&gt;mnt_root,
  			       stmnt-&gt;str + stmnt-&gt;mnt_point,
  			       stmnt-&gt;str + stmnt-&gt;mnt_opts);
  			free(stmnt);
  		}
  	}

  	exit(0);
  }

* patches from https://lore.kernel.org/r/20240719-work-mount-namespace-v1-0-834113cab0d2@kernel.org:
  nsfs: iterate through mount namespaces
  file: add fput() cleanup helper
  fs: add put_mnt_ns() cleanup helper
  fs: allow mount namespace fd

Signed-off-by: Christian Brauner &lt;brauner@kernel.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Christian Brauner &lt;brauner@kernel.org&gt; says:

Recently, we added the ability to list mounts in other mount namespaces
and the ability to retrieve namespace file descriptors without having to
go through procfs by deriving them from pidfds.

This extends nsfs in two ways:

(1) Add the ability to retrieve information about a mount namespace via
    NS_MNT_GET_INFO. This will return the mount namespace id and the
    number of mounts currently in the mount namespace. The number of
    mounts can be used to size the buffer that needs to be used for
    listmount() and is in general useful without having to actually
    iterate through all the mounts.

    The structure is extensible.

(2) Add the ability to iterate through all mount namespaces over which
    the caller holds privilege returning the file descriptor for the
    next or previous mount namespace.

    To retrieve a mount namespace the caller must be privileged wrt to
    it's owning user namespace. This means that PID 1 on the host can
    list all mounts in all mount namespaces or that a container can list
    all mounts of its nested containers.

    Optionally pass a structure for NS_MNT_GET_INFO with
    NS_MNT_GET_{PREV,NEXT} to retrieve information about the mount
    namespace in one go.

(1) and (2) can be implemented for other namespace types easily.

Together with recent api additions this means one can iterate through
all mounts in all mount namespaces without ever touching procfs. Here's
a sample program list_all_mounts_everywhere.c:

  // SPDX-License-Identifier: GPL-2.0-or-later

  #define _GNU_SOURCE
  #include &lt;asm/unistd.h&gt;
  #include &lt;assert.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;getopt.h&gt;
  #include &lt;linux/stat.h&gt;
  #include &lt;sched.h&gt;
  #include &lt;stddef.h&gt;
  #include &lt;stdint.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;string.h&gt;
  #include &lt;sys/ioctl.h&gt;
  #include &lt;sys/param.h&gt;
  #include &lt;sys/pidfd.h&gt;
  #include &lt;sys/stat.h&gt;
  #include &lt;sys/statfs.h&gt;

  #define die_errno(format, ...)                                             \
  	do {                                                               \
  		fprintf(stderr, "%m | %s: %d: %s: " format "\n", __FILE__, \
  			__LINE__, __func__, ##__VA_ARGS__);                \
  		exit(EXIT_FAILURE);                                        \
  	} while (0)

  /* Get the id for a mount namespace */
  #define NS_GET_MNTNS_ID		_IO(0xb7, 0x5)
  /* Get next mount namespace. */

  struct mnt_ns_info {
  	__u32 size;
  	__u32 nr_mounts;
  	__u64 mnt_ns_id;
  };

  #define MNT_NS_INFO_SIZE_VER0 16 /* size of first published struct */

  /* Get information about namespace. */
  #define NS_MNT_GET_INFO		_IOR(0xb7, 10, struct mnt_ns_info)
  /* Get next namespace. */
  #define NS_MNT_GET_NEXT		_IOR(0xb7, 11, struct mnt_ns_info)
  /* Get previous namespace. */
  #define NS_MNT_GET_PREV		_IOR(0xb7, 12, struct mnt_ns_info)

  #define PIDFD_GET_MNT_NAMESPACE _IO(0xFF, 3)

  #define STATX_MNT_ID_UNIQUE	0x00004000U	/* Want/got extended stx_mount_id */

  #define __NR_listmount 458
  #define __NR_statmount 457

  /*
   * @mask bits for statmount(2)
   */
  #define STATMOUNT_SB_BASIC		0x00000001U     /* Want/got sb_... */
  #define STATMOUNT_MNT_BASIC		0x00000002U	/* Want/got mnt_... */
  #define STATMOUNT_PROPAGATE_FROM	0x00000004U	/* Want/got propagate_from */
  #define STATMOUNT_MNT_ROOT		0x00000008U	/* Want/got mnt_root  */
  #define STATMOUNT_MNT_POINT		0x00000010U	/* Want/got mnt_point */
  #define STATMOUNT_FS_TYPE		0x00000020U	/* Want/got fs_type */
  #define STATMOUNT_MNT_NS_ID             0x00000040U     /* Want/got mnt_ns_id */
  #define STATMOUNT_MNT_OPTS              0x00000080U     /* Want/got mnt_opts */

  struct statmount {
  	__u32 size;		/* Total size, including strings */
  	__u32 mnt_opts;
  	__u64 mask;		/* What results were written */
  	__u32 sb_dev_major;	/* Device ID */
  	__u32 sb_dev_minor;
  	__u64 sb_magic;		/* ..._SUPER_MAGIC */
  	__u32 sb_flags;		/* SB_{RDONLY,SYNCHRONOUS,DIRSYNC,LAZYTIME} */
  	__u32 fs_type;		/* [str] Filesystem type */
  	__u64 mnt_id;		/* Unique ID of mount */
  	__u64 mnt_parent_id;	/* Unique ID of parent (for root == mnt_id) */
  	__u32 mnt_id_old;	/* Reused IDs used in proc/.../mountinfo */
  	__u32 mnt_parent_id_old;
  	__u64 mnt_attr;		/* MOUNT_ATTR_... */
  	__u64 mnt_propagation;	/* MS_{SHARED,SLAVE,PRIVATE,UNBINDABLE} */
  	__u64 mnt_peer_group;	/* ID of shared peer group */
  	__u64 mnt_master;	/* Mount receives propagation from this ID */
  	__u64 propagate_from;	/* Propagation from in current namespace */
  	__u32 mnt_root;		/* [str] Root of mount relative to root of fs */
  	__u32 mnt_point;	/* [str] Mountpoint relative to current root */
  	__u64 mnt_ns_id;
  	__u64 __spare2[49];
  	char str[];		/* Variable size part containing strings */
  };

  struct mnt_id_req {
  	__u32 size;
  	__u32 spare;
  	__u64 mnt_id;
  	__u64 param;
  	__u64 mnt_ns_id;
  };

  #define MNT_ID_REQ_SIZE_VER1	32 /* sizeof second published struct */

  #define LSMT_ROOT		0xffffffffffffffff	/* root mount */

  static int __statmount(__u64 mnt_id, __u64 mnt_ns_id, __u64 mask,
  		       struct statmount *stmnt, size_t bufsize, unsigned int flags)
  {
  	struct mnt_id_req req = {
  		.size = MNT_ID_REQ_SIZE_VER1,
  		.mnt_id = mnt_id,
  		.param = mask,
  		.mnt_ns_id = mnt_ns_id,
  	};

  	return syscall(__NR_statmount, &amp;req, stmnt, bufsize, flags);
  }

  static struct statmount *sys_statmount(__u64 mnt_id, __u64 mnt_ns_id,
  				       __u64 mask, unsigned int flags)
  {
  	size_t bufsize = 1 &lt;&lt; 15;
  	struct statmount *stmnt = NULL, *tmp = NULL;
  	int ret;

  	for (;;) {
  		tmp = realloc(stmnt, bufsize);
  		if (!tmp)
  			goto out;

  		stmnt = tmp;
  		ret = __statmount(mnt_id, mnt_ns_id, mask, stmnt, bufsize, flags);
  		if (!ret)
  			return stmnt;

  		if (errno != EOVERFLOW)
  			goto out;

  		bufsize &lt;&lt;= 1;
  		if (bufsize &gt;= UINT_MAX / 2)
  			goto out;

  	}

  out:
  	free(stmnt);
  	printf("statmount failed");
  	return NULL;
  }

  static ssize_t sys_listmount(__u64 mnt_id, __u64 last_mnt_id, __u64 mnt_ns_id,
  			     __u64 list[], size_t num, unsigned int flags)
  {
  	struct mnt_id_req req = {
  		.size = MNT_ID_REQ_SIZE_VER1,
  		.mnt_id = mnt_id,
  		.param = last_mnt_id,
  		.mnt_ns_id = mnt_ns_id,
  	};

  	return syscall(__NR_listmount, &amp;req, list, num, flags);
  }

  int main(int argc, char *argv[])
  {
  #define LISTMNT_BUFFER 10
  	__u64 list[LISTMNT_BUFFER], last_mnt_id = 0;
  	int ret, pidfd, fd_mntns;
  	struct mnt_ns_info info = {};

  	pidfd = pidfd_open(getpid(), 0);
  	if (pidfd &lt; 0)
  		die_errno("pidfd_open failed");

  	fd_mntns = ioctl(pidfd, PIDFD_GET_MNT_NAMESPACE, 0);
  	if (fd_mntns &lt; 0)
  		die_errno("ioctl(PIDFD_GET_MNT_NAMESPACE) failed");

  	ret = ioctl(fd_mntns, NS_MNT_GET_INFO, &amp;info);
  	if (ret &lt; 0)
  		die_errno("ioctl(NS_GET_MNTNS_ID) failed");

  	printf("Listing %u mounts for mount namespace %d:%llu\n", info.nr_mounts, fd_mntns, info.mnt_ns_id);
  	for (;;) {
  		ssize_t nr_mounts;
  	next:
  		nr_mounts = sys_listmount(LSMT_ROOT, last_mnt_id, info.mnt_ns_id, list, LISTMNT_BUFFER, 0);
  		if (nr_mounts &lt;= 0) {
  			printf("Finished listing mounts for mount namespace %d:%llu\n\n", fd_mntns, info.mnt_ns_id);
  			ret = ioctl(fd_mntns, NS_MNT_GET_NEXT, 0);
  			if (ret &lt; 0)
  				die_errno("ioctl(NS_MNT_GET_NEXT) failed");
  			close(ret);
  			ret = ioctl(fd_mntns, NS_MNT_GET_NEXT, &amp;info);
  			if (ret &lt; 0) {
  				if (errno == ENOENT) {
  					printf("Finished listing all mount namespaces\n");
  					exit(0);
  				}
  				die_errno("ioctl(NS_MNT_GET_NEXT) failed");
  			}
  			close(fd_mntns);
  			fd_mntns = ret;
  			last_mnt_id = 0;
  			printf("Listing %u mounts for mount namespace %d:%llu\n", info.nr_mounts, fd_mntns, info.mnt_ns_id);
  			goto next;
  		}

  		for (size_t cur = 0; cur &lt; nr_mounts; cur++) {
  			struct statmount *stmnt;

  			last_mnt_id = list[cur];

  			stmnt = sys_statmount(last_mnt_id, info.mnt_ns_id,
  					      STATMOUNT_SB_BASIC |
  					      STATMOUNT_MNT_BASIC |
  					      STATMOUNT_MNT_ROOT |
  					      STATMOUNT_MNT_POINT |
  					      STATMOUNT_MNT_NS_ID |
  					      STATMOUNT_MNT_OPTS |
  					      STATMOUNT_FS_TYPE,
  					  0);
  			if (!stmnt) {
  				printf("Failed to statmount(%llu) in mount namespace(%llu)\n", last_mnt_id, info.mnt_ns_id);
  				continue;
  			}

  			printf("mnt_id(%u/%llu) | mnt_parent_id(%u/%llu): %s @ %s ==&gt; %s with options: %s\n",
  			       stmnt-&gt;mnt_id_old, stmnt-&gt;mnt_id,
  			       stmnt-&gt;mnt_parent_id_old, stmnt-&gt;mnt_parent_id,
  			       stmnt-&gt;str + stmnt-&gt;fs_type,
  			       stmnt-&gt;str + stmnt-&gt;mnt_root,
  			       stmnt-&gt;str + stmnt-&gt;mnt_point,
  			       stmnt-&gt;str + stmnt-&gt;mnt_opts);
  			free(stmnt);
  		}
  	}

  	exit(0);
  }

* patches from https://lore.kernel.org/r/20240719-work-mount-namespace-v1-0-834113cab0d2@kernel.org:
  nsfs: iterate through mount namespaces
  file: add fput() cleanup helper
  fs: add put_mnt_ns() cleanup helper
  fs: allow mount namespace fd

Signed-off-by: Christian Brauner &lt;brauner@kernel.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>nsfs: iterate through mount namespaces</title>
<updated>2024-08-09T10:46:59+00:00</updated>
<author>
<name>Christian Brauner</name>
<email>brauner@kernel.org</email>
</author>
<published>2024-07-19T11:41:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=a1d220d9dafa8d76ba60a784a1016c3134e6a1e8'/>
<id>a1d220d9dafa8d76ba60a784a1016c3134e6a1e8</id>
<content type='text'>
It is already possible to list mounts in other mount namespaces and to
retrieve namespace file descriptors without having to go through procfs
by deriving them from pidfds.

Augment these abilities by adding the ability to retrieve information
about a mount namespace via NS_MNT_GET_INFO. This will return the mount
namespace id and the number of mounts currently in the mount namespace.
The number of mounts can be used to size the buffer that needs to be
used for listmount() and is in general useful without having to actually
iterate through all the mounts. The structure is extensible.

And add the ability to iterate through all mount namespaces over which
the caller holds privilege returning the file descriptor for the next or
previous mount namespace.

To retrieve a mount namespace the caller must be privileged wrt to it's
owning user namespace. This means that PID 1 on the host can list all
mounts in all mount namespaces or that a container can list all mounts
of its nested containers.

Optionally pass a structure for NS_MNT_GET_INFO with
NS_MNT_GET_{PREV,NEXT} to retrieve information about the mount namespace
in one go. Both ioctls can be implemented for other namespace types
easily.

Together with recent api additions this means one can iterate through
all mounts in all mount namespaces without ever touching procfs.

Link: https://lore.kernel.org/r/20240719-work-mount-namespace-v1-5-834113cab0d2@kernel.org
Reviewed-by: Josef Bacik &lt;josef@toxicpanda.com&gt;
Reviewed-by: Jeff Layton &lt;jlayton@kernel.org&gt;
Signed-off-by: Christian Brauner &lt;brauner@kernel.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
It is already possible to list mounts in other mount namespaces and to
retrieve namespace file descriptors without having to go through procfs
by deriving them from pidfds.

Augment these abilities by adding the ability to retrieve information
about a mount namespace via NS_MNT_GET_INFO. This will return the mount
namespace id and the number of mounts currently in the mount namespace.
The number of mounts can be used to size the buffer that needs to be
used for listmount() and is in general useful without having to actually
iterate through all the mounts. The structure is extensible.

And add the ability to iterate through all mount namespaces over which
the caller holds privilege returning the file descriptor for the next or
previous mount namespace.

To retrieve a mount namespace the caller must be privileged wrt to it's
owning user namespace. This means that PID 1 on the host can list all
mounts in all mount namespaces or that a container can list all mounts
of its nested containers.

Optionally pass a structure for NS_MNT_GET_INFO with
NS_MNT_GET_{PREV,NEXT} to retrieve information about the mount namespace
in one go. Both ioctls can be implemented for other namespace types
easily.

Together with recent api additions this means one can iterate through
all mounts in all mount namespaces without ever touching procfs.

Link: https://lore.kernel.org/r/20240719-work-mount-namespace-v1-5-834113cab0d2@kernel.org
Reviewed-by: Josef Bacik &lt;josef@toxicpanda.com&gt;
Reviewed-by: Jeff Layton &lt;jlayton@kernel.org&gt;
Signed-off-by: Christian Brauner &lt;brauner@kernel.org&gt;
</pre>
</div>
</content>
</entry>
</feed>
