All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ovl: add ioctls to retrieve layer file descriptors
@ 2026-07-08  9:58 Giuseppe Scrivano
  2026-07-08 10:24 ` Miklos Szeredi
  2026-07-08 10:40 ` Amir Goldstein
  0 siblings, 2 replies; 20+ messages in thread
From: Giuseppe Scrivano @ 2026-07-08  9:58 UTC (permalink / raw)
  To: linux-unionfs; +Cc: linux-fsdevel, linux-api

Add two ioctls to overlay filesystem to allow userspace to retrieve
information about the overlay layers:

OVL_IOC_OPEN_LAYER:     return an O_PATH fd to the root of a layer.
                        arg == 0 returns the upper layer (-ENOENT if
                        no upper is configured), arg >= 1 returns
                        lower layers (-ENOENT if index is out of
                        range).
OVL_IOC_GET_LAYERS_INFO: copy a struct ovl_layers_info to userspace
                        with numlower, numlowerdata, and has_upper.

The ioctls work on any overlayfs file or directory and require
CAP_SYS_ADMIN in the mounter's user namespace.

The UAPI constants and struct are defined in include/uapi/linux/overlay.h.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
---
 MAINTAINERS                  |  1 +
 fs/overlayfs/file.c          |  2 ++
 fs/overlayfs/overlayfs.h     |  4 +++
 fs/overlayfs/ovl_entry.h     |  2 ++
 fs/overlayfs/params.c        | 10 ++++++
 fs/overlayfs/params.h        |  1 +
 fs/overlayfs/readdir.c       |  2 ++
 fs/overlayfs/super.c         | 70 ++++++++++++++++++++++++++++++++++++
 include/uapi/linux/overlay.h | 30 ++++++++++++++++
 9 files changed, 122 insertions(+)
 create mode 100644 include/uapi/linux/overlay.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 25453040dffb..b64c696686e4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20368,6 +20368,7 @@ S:	Supported
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs.git
 F:	Documentation/filesystems/overlayfs.rst
 F:	fs/overlayfs/
+F:	include/uapi/linux/overlay.h
 
 P54 WIRELESS DRIVER
 M:	Christian Lamparter <chunkeey@googlemail.com>
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
index 27cc07738f33..fc9c448c5959 100644
--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -649,4 +649,6 @@ const struct file_operations ovl_file_operations = {
 	.copy_file_range	= ovl_copy_file_range,
 	.remap_file_range	= ovl_remap_file_range,
 	.setlease		= generic_setlease,
+	.unlocked_ioctl		= ovl_ioctl,
+	.compat_ioctl		= compat_ptr_ioctl,
 };
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index b75df37f70ac..10f7ef8cb78c 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -8,6 +8,7 @@
 #include <linux/uuid.h>
 #include <linux/fs.h>
 #include <linux/fsverity.h>
+#include <uapi/linux/overlay.h>
 #include <linux/namei.h>
 #include <linux/posix_acl.h>
 #include <linux/posix_acl_xattr.h>
@@ -908,6 +909,9 @@ void ovl_tempname(char name[OVL_TEMPNAME_SIZE]);
 struct dentry *ovl_create_temp(struct ovl_fs *ofs, struct dentry *workdir,
 			       struct ovl_cattr *attr);
 
+/* super.c */
+long ovl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+
 /* file.c */
 extern const struct file_operations ovl_file_operations;
 int ovl_real_fileattr_get(const struct path *realpath, struct file_kattr *fa);
diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
index 80cad4ea96a3..b8f4bca89a27 100644
--- a/fs/overlayfs/ovl_entry.h
+++ b/fs/overlayfs/ovl_entry.h
@@ -35,6 +35,8 @@ struct ovl_layer {
 	struct vfsmount *mnt;
 	/* Trap in ovl inode cache */
 	struct inode *trap;
+	/* Keeps the original fsmount file alive for OVL_IOC_OPEN_LAYER */
+	struct file *origin;
 	struct ovl_sb *fs;
 	/* Index of this layer in fs root (upper idx == 0) */
 	int idx;
diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c
index c93fcaa45d4a..92d1a56178f2 100644
--- a/fs/overlayfs/params.c
+++ b/fs/overlayfs/params.c
@@ -482,6 +482,11 @@ static int ovl_parse_layer(struct fs_context *fc, struct fs_parameter *param,
 			return PTR_ERR(layer_name);
 
 		err = ovl_do_parse_layer(fc, layer_name, &layer_path, layer);
+		if (!err && !is_upper_layer(layer)) {
+			struct ovl_fs_context *ctx = fc->fs_private;
+
+			ctx->lower[ctx->nr - 1].origin = get_file(param->file);
+		}
 		break;
 	}
 	default:
@@ -504,6 +509,9 @@ static void ovl_reset_lowerdirs(struct ovl_fs_context *ctx)
 		path_put(&l->path);
 		kfree(l->name);
 		l->name = NULL;
+		if (l->origin)
+			fput(l->origin);
+		l->origin = NULL;
 	}
 	ctx->nr = 0;
 	ctx->nr_data = 0;
@@ -856,6 +864,8 @@ void ovl_free_fs(struct ovl_fs *ofs)
 	mounts = (struct vfsmount **) ofs->config.lowerdirs;
 	for (i = 0; i < ofs->numlayer; i++) {
 		iput(ofs->layers[i].trap);
+		if (ofs->layers[i].origin)
+			fput(ofs->layers[i].origin);
 		kfree(ofs->config.lowerdirs[i]);
 		mounts[i] = ofs->layers[i].mnt;
 	}
diff --git a/fs/overlayfs/params.h b/fs/overlayfs/params.h
index ffd53cdd8482..1d8fe8fbaca2 100644
--- a/fs/overlayfs/params.h
+++ b/fs/overlayfs/params.h
@@ -22,6 +22,7 @@ struct ovl_opt_set {
 struct ovl_fs_context_layer {
 	char *name;
 	struct path path;
+	struct file *origin;
 };
 
 struct ovl_fs_context {
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index e7fe29cb6028..7bab71c8bcc2 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -1069,6 +1069,8 @@ const struct file_operations ovl_dir_operations = {
 	.iterate_shared	= shared_ovl_iterate,
 	.llseek		= ovl_dir_llseek,
 	.fsync		= ovl_dir_fsync,
+	.unlocked_ioctl	= ovl_ioctl,
+	.compat_ioctl	= compat_ptr_ioctl,
 	.release	= ovl_dir_release,
 	.setlease	= generic_setlease,
 };
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 60f0b7ceef0a..d143002e74b2 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1107,6 +1107,8 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
 		 */
 		mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;
 
+		layers[ofs->numlayer].origin = l->origin;
+		l->origin = NULL;
 		layers[ofs->numlayer].trap = trap;
 		layers[ofs->numlayer].mnt = mnt;
 		layers[ofs->numlayer].idx = ofs->numlayer;
@@ -1568,6 +1570,74 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
 	return err;
 }
 
+static long ovl_ioctl_open_layer(struct file *filp, unsigned long arg)
+{
+	struct super_block *sb = file_inode(filp)->i_sb;
+	struct ovl_fs *ofs = OVL_FS(sb);
+	struct path root;
+	struct file *f;
+	int fd;
+
+	if (arg >= ofs->numlayer)
+		return -ENOENT;
+	if (arg == 0 && !ovl_upper_mnt(ofs))
+		return -ENOENT;
+	if (!ofs->layers[arg].origin)
+		return -EOPNOTSUPP;
+
+	root.mnt = mntget(ofs->layers[arg].origin->f_path.mnt);
+	root.dentry = dget(root.mnt->mnt_root);
+
+	fd = get_unused_fd_flags(O_CLOEXEC);
+	if (fd < 0) {
+		path_put(&root);
+		return fd;
+	}
+
+	f = dentry_open(&root, O_PATH | O_NOFOLLOW, current_cred());
+	path_put(&root);
+	if (IS_ERR(f)) {
+		put_unused_fd(fd);
+		return PTR_ERR(f);
+	}
+
+	fd_install(fd, f);
+	return fd;
+}
+
+static long ovl_ioctl_get_layers_info(struct file *filp, unsigned long arg)
+{
+	struct super_block *sb = file_inode(filp)->i_sb;
+	struct ovl_fs *ofs = OVL_FS(sb);
+	struct ovl_layers_info info = {
+		.numlower = ofs->numlayer - 1,
+		.numlowerdata = ofs->numdatalayer,
+		.has_upper = !!ovl_upper_mnt(ofs),
+	};
+
+	if (copy_to_user((void __user *)arg, &info, sizeof(info)))
+		return -EFAULT;
+
+	return 0;
+}
+
+long ovl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct ovl_fs *ofs = OVL_FS(file_inode(filp)->i_sb);
+
+	if (!ns_capable(ofs->creator_cred->user_ns, CAP_SYS_ADMIN))
+		return -EPERM;
+
+	switch (cmd) {
+	case OVL_IOC_OPEN_LAYER:
+		return ovl_ioctl_open_layer(filp, arg);
+	case OVL_IOC_GET_LAYERS_INFO:
+		return ovl_ioctl_get_layers_info(filp, arg);
+	default:
+		return -ENOTTY;
+	}
+}
+
 struct file_system_type ovl_fs_type = {
 	.owner			= THIS_MODULE,
 	.name			= "overlay",
diff --git a/include/uapi/linux/overlay.h b/include/uapi/linux/overlay.h
new file mode 100644
index 000000000000..c92ccecd9e21
--- /dev/null
+++ b/include/uapi/linux/overlay.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_OVERLAY_H
+#define _UAPI_LINUX_OVERLAY_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/**
+ * struct ovl_layers_info - overlay layer configuration summary
+ * @numlower:     number of lower (metadata) layers
+ * @numlowerdata: number of data-only lower layers
+ * @has_upper:    1 if an upper layer is configured, 0 otherwise
+ */
+struct ovl_layers_info {
+	__u32 numlower;
+	__u32 numlowerdata;
+	__u32 has_upper;
+};
+
+/*
+ * Return an O_PATH fd to the root of the specified overlay layer.
+ * arg == 0: upper layer (returns -ENOENT if no upper is configured)
+ * arg >= 1: lower layers (returns -ENOENT if index is out of range)
+ */
+#define OVL_IOC_OPEN_LAYER	_IO('O', 1)
+
+/* Retrieve overlay layer configuration into struct ovl_layers_info. */
+#define OVL_IOC_GET_LAYERS_INFO	_IOR('O', 2, struct ovl_layers_info)
+
+#endif /* _UAPI_LINUX_OVERLAY_H */
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08  9:58 [PATCH] ovl: add ioctls to retrieve layer file descriptors Giuseppe Scrivano
@ 2026-07-08 10:24 ` Miklos Szeredi
  2026-07-08 12:27   ` Giuseppe Scrivano
  2026-07-08 10:40 ` Amir Goldstein
  1 sibling, 1 reply; 20+ messages in thread
From: Miklos Szeredi @ 2026-07-08 10:24 UTC (permalink / raw)
  To: Giuseppe Scrivano; +Cc: linux-unionfs, linux-fsdevel, linux-api

On Wed, 8 Jul 2026 at 12:00, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>
> Add two ioctls to overlay filesystem to allow userspace to retrieve
> information about the overlay layers:
>
> OVL_IOC_OPEN_LAYER:     return an O_PATH fd to the root of a layer.
>                         arg == 0 returns the upper layer (-ENOENT if
>                         no upper is configured), arg >= 1 returns
>                         lower layers (-ENOENT if index is out of
>                         range).

We could do this with a plain open() call.  Something like the magic
symlinks we have under /proc/PID/fd/.   Question is where could these
live...

> OVL_IOC_GET_LAYERS_INFO: copy a struct ovl_layers_info to userspace
>                         with numlower, numlowerdata, and has_upper.

Isn't this info obtainable via statmount(2) already?  If not, it
should be there, instead of a specialized ioctl.

> --- a/fs/overlayfs/ovl_entry.h
> +++ b/fs/overlayfs/ovl_entry.h
> @@ -35,6 +35,8 @@ struct ovl_layer {
>         struct vfsmount *mnt;
>         /* Trap in ovl inode cache */
>         struct inode *trap;
> +       /* Keeps the original fsmount file alive for OVL_IOC_OPEN_LAYER */
> +       struct file *origin;

Don't need to keep the file open: the only info missing is the
original vfsmount, everything else is already there to reconstruct the
file.

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08  9:58 [PATCH] ovl: add ioctls to retrieve layer file descriptors Giuseppe Scrivano
  2026-07-08 10:24 ` Miklos Szeredi
@ 2026-07-08 10:40 ` Amir Goldstein
  1 sibling, 0 replies; 20+ messages in thread
From: Amir Goldstein @ 2026-07-08 10:40 UTC (permalink / raw)
  To: Giuseppe Scrivano; +Cc: linux-unionfs, linux-fsdevel, linux-api, Miklos Szeredi

On Wed, Jul 8, 2026 at 12:00 PM Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>
> Add two ioctls to overlay filesystem to allow userspace to retrieve
> information about the overlay layers:
>
> OVL_IOC_OPEN_LAYER:     return an O_PATH fd to the root of a layer.
>                         arg == 0 returns the upper layer (-ENOENT if
>                         no upper is configured), arg >= 1 returns
>                         lower layers (-ENOENT if index is out of
>                         range).
> OVL_IOC_GET_LAYERS_INFO: copy a struct ovl_layers_info to userspace
>                         with numlower, numlowerdata, and has_upper.
>
> The ioctls work on any overlayfs file or directory and require
> CAP_SYS_ADMIN in the mounter's user namespace.
>
> The UAPI constants and struct are defined in include/uapi/linux/overlay.h.
>
> Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
> ---
>  MAINTAINERS                  |  1 +
>  fs/overlayfs/file.c          |  2 ++
>  fs/overlayfs/overlayfs.h     |  4 +++
>  fs/overlayfs/ovl_entry.h     |  2 ++
>  fs/overlayfs/params.c        | 10 ++++++
>  fs/overlayfs/params.h        |  1 +
>  fs/overlayfs/readdir.c       |  2 ++
>  fs/overlayfs/super.c         | 70 ++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/overlay.h | 30 ++++++++++++++++
>  9 files changed, 122 insertions(+)
>  create mode 100644 include/uapi/linux/overlay.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 25453040dffb..b64c696686e4 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -20368,6 +20368,7 @@ S:      Supported
>  T:     git git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs.git
>  F:     Documentation/filesystems/overlayfs.rst
>  F:     fs/overlayfs/
> +F:     include/uapi/linux/overlay.h


overlayfs.h please

>
>  P54 WIRELESS DRIVER
>  M:     Christian Lamparter <chunkeey@googlemail.com>
> diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
> index 27cc07738f33..fc9c448c5959 100644
> --- a/fs/overlayfs/file.c
> +++ b/fs/overlayfs/file.c
> @@ -649,4 +649,6 @@ const struct file_operations ovl_file_operations = {
>         .copy_file_range        = ovl_copy_file_range,
>         .remap_file_range       = ovl_remap_file_range,
>         .setlease               = generic_setlease,
> +       .unlocked_ioctl         = ovl_ioctl,
> +       .compat_ioctl           = compat_ptr_ioctl,
>  };
> diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
> index b75df37f70ac..10f7ef8cb78c 100644
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@ -8,6 +8,7 @@
>  #include <linux/uuid.h>
>  #include <linux/fs.h>
>  #include <linux/fsverity.h>
> +#include <uapi/linux/overlay.h>
>  #include <linux/namei.h>
>  #include <linux/posix_acl.h>
>  #include <linux/posix_acl_xattr.h>
> @@ -908,6 +909,9 @@ void ovl_tempname(char name[OVL_TEMPNAME_SIZE]);
>  struct dentry *ovl_create_temp(struct ovl_fs *ofs, struct dentry *workdir,
>                                struct ovl_cattr *attr);
>
> +/* super.c */
> +long ovl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
> +
>  /* file.c */
>  extern const struct file_operations ovl_file_operations;
>  int ovl_real_fileattr_get(const struct path *realpath, struct file_kattr *fa);
> diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
> index 80cad4ea96a3..b8f4bca89a27 100644
> --- a/fs/overlayfs/ovl_entry.h
> +++ b/fs/overlayfs/ovl_entry.h
> @@ -35,6 +35,8 @@ struct ovl_layer {
>         struct vfsmount *mnt;
>         /* Trap in ovl inode cache */
>         struct inode *trap;
> +       /* Keeps the original fsmount file alive for OVL_IOC_OPEN_LAYER */
> +       struct file *origin;

as Miklos wrote, keep the file is an overkill

>         struct ovl_sb *fs;
>         /* Index of this layer in fs root (upper idx == 0) */
>         int idx;
> diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c
> index c93fcaa45d4a..92d1a56178f2 100644
> --- a/fs/overlayfs/params.c
> +++ b/fs/overlayfs/params.c
> @@ -482,6 +482,11 @@ static int ovl_parse_layer(struct fs_context *fc, struct fs_parameter *param,
>                         return PTR_ERR(layer_name);
>
>                 err = ovl_do_parse_layer(fc, layer_name, &layer_path, layer);
> +               if (!err && !is_upper_layer(layer)) {
> +                       struct ovl_fs_context *ctx = fc->fs_private;
> +
> +                       ctx->lower[ctx->nr - 1].origin = get_file(param->file);
> +               }
>                 break;
>         }
>         default:
> @@ -504,6 +509,9 @@ static void ovl_reset_lowerdirs(struct ovl_fs_context *ctx)
>                 path_put(&l->path);
>                 kfree(l->name);
>                 l->name = NULL;
> +               if (l->origin)
> +                       fput(l->origin);
> +               l->origin = NULL;
>         }
>         ctx->nr = 0;
>         ctx->nr_data = 0;
> @@ -856,6 +864,8 @@ void ovl_free_fs(struct ovl_fs *ofs)
>         mounts = (struct vfsmount **) ofs->config.lowerdirs;
>         for (i = 0; i < ofs->numlayer; i++) {
>                 iput(ofs->layers[i].trap);
> +               if (ofs->layers[i].origin)
> +                       fput(ofs->layers[i].origin);
>                 kfree(ofs->config.lowerdirs[i]);
>                 mounts[i] = ofs->layers[i].mnt;
>         }
> diff --git a/fs/overlayfs/params.h b/fs/overlayfs/params.h
> index ffd53cdd8482..1d8fe8fbaca2 100644
> --- a/fs/overlayfs/params.h
> +++ b/fs/overlayfs/params.h
> @@ -22,6 +22,7 @@ struct ovl_opt_set {
>  struct ovl_fs_context_layer {
>         char *name;
>         struct path path;
> +       struct file *origin;
>  };
>
>  struct ovl_fs_context {
> diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
> index e7fe29cb6028..7bab71c8bcc2 100644
> --- a/fs/overlayfs/readdir.c
> +++ b/fs/overlayfs/readdir.c
> @@ -1069,6 +1069,8 @@ const struct file_operations ovl_dir_operations = {
>         .iterate_shared = shared_ovl_iterate,
>         .llseek         = ovl_dir_llseek,
>         .fsync          = ovl_dir_fsync,
> +       .unlocked_ioctl = ovl_ioctl,
> +       .compat_ioctl   = compat_ptr_ioctl,
>         .release        = ovl_dir_release,
>         .setlease       = generic_setlease,
>  };
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index 60f0b7ceef0a..d143002e74b2 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -1107,6 +1107,8 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
>                  */
>                 mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;
>
> +               layers[ofs->numlayer].origin = l->origin;
> +               l->origin = NULL;
>                 layers[ofs->numlayer].trap = trap;
>                 layers[ofs->numlayer].mnt = mnt;
>                 layers[ofs->numlayer].idx = ofs->numlayer;
> @@ -1568,6 +1570,74 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
>         return err;
>  }
>
> +static long ovl_ioctl_open_layer(struct file *filp, unsigned long arg)
> +{
> +       struct super_block *sb = file_inode(filp)->i_sb;
> +       struct ovl_fs *ofs = OVL_FS(sb);
> +       struct path root;
> +       struct file *f;
> +       int fd;
> +
> +       if (arg >= ofs->numlayer)
> +               return -ENOENT;
> +       if (arg == 0 && !ovl_upper_mnt(ofs))
> +               return -ENOENT;
> +       if (!ofs->layers[arg].origin)
> +               return -EOPNOTSUPP;
> +
> +       root.mnt = mntget(ofs->layers[arg].origin->f_path.mnt);
> +       root.dentry = dget(root.mnt->mnt_root);
> +
> +       fd = get_unused_fd_flags(O_CLOEXEC);
> +       if (fd < 0) {
> +               path_put(&root);
> +               return fd;
> +       }
> +
> +       f = dentry_open(&root, O_PATH | O_NOFOLLOW, current_cred());
> +       path_put(&root);
> +       if (IS_ERR(f)) {
> +               put_unused_fd(fd);
> +               return PTR_ERR(f);
> +       }
> +
> +       fd_install(fd, f);
> +       return fd;
> +}
> +
> +static long ovl_ioctl_get_layers_info(struct file *filp, unsigned long arg)
> +{
> +       struct super_block *sb = file_inode(filp)->i_sb;
> +       struct ovl_fs *ofs = OVL_FS(sb);
> +       struct ovl_layers_info info = {
> +               .numlower = ofs->numlayer - 1,
> +               .numlowerdata = ofs->numdatalayer,
> +               .has_upper = !!ovl_upper_mnt(ofs),
> +       };
> +
> +       if (copy_to_user((void __user *)arg, &info, sizeof(info)))
> +               return -EFAULT;
> +
> +       return 0;
> +}
> +
> +long ovl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> +{
> +       struct ovl_fs *ofs = OVL_FS(file_inode(filp)->i_sb);
> +
> +       if (!ns_capable(ofs->creator_cred->user_ns, CAP_SYS_ADMIN))
> +               return -EPERM;
> +
> +       switch (cmd) {
> +       case OVL_IOC_OPEN_LAYER:
> +               return ovl_ioctl_open_layer(filp, arg);
> +       case OVL_IOC_GET_LAYERS_INFO:
> +               return ovl_ioctl_get_layers_info(filp, arg);
> +       default:
> +               return -ENOTTY;
> +       }
> +}
> +
>  struct file_system_type ovl_fs_type = {
>         .owner                  = THIS_MODULE,
>         .name                   = "overlay",
> diff --git a/include/uapi/linux/overlay.h b/include/uapi/linux/overlay.h
> new file mode 100644
> index 000000000000..c92ccecd9e21
> --- /dev/null
> +++ b/include/uapi/linux/overlay.h

overlayfs.h please

> @@ -0,0 +1,30 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +#ifndef _UAPI_LINUX_OVERLAY_H
> +#define _UAPI_LINUX_OVERLAY_H
> +
> +#include <linux/ioctl.h>
> +#include <linux/types.h>
> +
> +/**
> + * struct ovl_layers_info - overlay layer configuration summary
> + * @numlower:     number of lower (metadata) layers
> + * @numlowerdata: number of data-only lower layers
> + * @has_upper:    1 if an upper layer is configured, 0 otherwise
> + */
> +struct ovl_layers_info {
> +       __u32 numlower;
> +       __u32 numlowerdata;
> +       __u32 has_upper;
> +};

Whether this stays as ioctl or statmount blob

please use:

__u32 flags;
__u32 pad;

and use a flag for has_upper so we can extend this data struct in the future.

Thanks,
Amir.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 10:24 ` Miklos Szeredi
@ 2026-07-08 12:27   ` Giuseppe Scrivano
  2026-07-08 13:23     ` Amir Goldstein
  2026-07-08 14:08     ` Miklos Szeredi
  0 siblings, 2 replies; 20+ messages in thread
From: Giuseppe Scrivano @ 2026-07-08 12:27 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: linux-unionfs, linux-fsdevel, linux-api

Miklos Szeredi <miklos@szeredi.hu> writes:

> On Wed, 8 Jul 2026 at 12:00, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>>
>> Add two ioctls to overlay filesystem to allow userspace to retrieve
>> information about the overlay layers:
>>
>> OVL_IOC_OPEN_LAYER:     return an O_PATH fd to the root of a layer.
>>                         arg == 0 returns the upper layer (-ENOENT if
>>                         no upper is configured), arg >= 1 returns
>>                         lower layers (-ENOENT if index is out of
>>                         range).
>
> We could do this with a plain open() call.  Something like the magic
> symlinks we have under /proc/PID/fd/.   Question is where could these
> live...

is there any existing user of such a mechanism?  I don't see any mount
specific info under /proc or /sys.

>
>> OVL_IOC_GET_LAYERS_INFO: copy a struct ovl_layers_info to userspace
>>                         with numlower, numlowerdata, and has_upper.
>
> Isn't this info obtainable via statmount(2) already?  If not, it
> should be there, instead of a specialized ioctl.

no that is not exposed by statmount and I don't see any way to export
file system specific data through it.  Do you've anything in mind?

>> --- a/fs/overlayfs/ovl_entry.h
>> +++ b/fs/overlayfs/ovl_entry.h
>> @@ -35,6 +35,8 @@ struct ovl_layer {
>>         struct vfsmount *mnt;
>>         /* Trap in ovl inode cache */
>>         struct inode *trap;
>> +       /* Keeps the original fsmount file alive for OVL_IOC_OPEN_LAYER */
>> +       struct file *origin;
>
> Don't need to keep the file open: the only info missing is the
> original vfsmount, everything else is already there to reconstruct the
> file.

I didn't manage to get that to work.  As soon as the userspace process
closes the mount fd that was passed to fsconfig, the anonymous mount
namespace is destroyed and dissolve_on_fput sets mnt->mnt_ns to NULL.

So whenever I try to use this mount again from userspace, it is not
usable because the mount namespace is empty, causing check_mnt() to
fail.

Do you have any suggestions on how to solve this problem?

Regards,
Giuseppe


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 12:27   ` Giuseppe Scrivano
@ 2026-07-08 13:23     ` Amir Goldstein
  2026-07-08 13:44       ` Giuseppe Scrivano
  2026-07-08 14:08     ` Miklos Szeredi
  1 sibling, 1 reply; 20+ messages in thread
From: Amir Goldstein @ 2026-07-08 13:23 UTC (permalink / raw)
  To: Giuseppe Scrivano; +Cc: Miklos Szeredi, linux-unionfs, linux-fsdevel, linux-api

On Wed, Jul 8, 2026 at 2:31 PM Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>
> Miklos Szeredi <miklos@szeredi.hu> writes:
>
> > On Wed, 8 Jul 2026 at 12:00, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
> >>
> >> Add two ioctls to overlay filesystem to allow userspace to retrieve
> >> information about the overlay layers:
> >>
> >> OVL_IOC_OPEN_LAYER:     return an O_PATH fd to the root of a layer.
> >>                         arg == 0 returns the upper layer (-ENOENT if
> >>                         no upper is configured), arg >= 1 returns
> >>                         lower layers (-ENOENT if index is out of
> >>                         range).
> >
> > We could do this with a plain open() call.  Something like the magic
> > symlinks we have under /proc/PID/fd/.   Question is where could these
> > live...
>
> is there any existing user of such a mechanism?  I don't see any mount
> specific info under /proc or /sys.
>
> >
> >> OVL_IOC_GET_LAYERS_INFO: copy a struct ovl_layers_info to userspace
> >>                         with numlower, numlowerdata, and has_upper.
> >
> > Isn't this info obtainable via statmount(2) already?  If not, it
> > should be there, instead of a specialized ioctl.
>
> no that is not exposed by statmount and I don't see any way to export
> file system specific data through it.  Do you've anything in mind?
>
> >> --- a/fs/overlayfs/ovl_entry.h
> >> +++ b/fs/overlayfs/ovl_entry.h
> >> @@ -35,6 +35,8 @@ struct ovl_layer {
> >>         struct vfsmount *mnt;
> >>         /* Trap in ovl inode cache */
> >>         struct inode *trap;
> >> +       /* Keeps the original fsmount file alive for OVL_IOC_OPEN_LAYER */
> >> +       struct file *origin;
> >
> > Don't need to keep the file open: the only info missing is the
> > original vfsmount, everything else is already there to reconstruct the
> > file.
>
> I didn't manage to get that to work.  As soon as the userspace process
> closes the mount fd that was passed to fsconfig, the anonymous mount
> namespace is destroyed and dissolve_on_fput sets mnt->mnt_ns to NULL.
>
> So whenever I try to use this mount again from userspace, it is not
> usable because the mount namespace is empty, causing check_mnt() to
> fail.
>
> Do you have any suggestions on how to solve this problem?

The suggestion was to store origin->f_path->mnt instead of storing origin file,
because you only end up using the origin vfsmount.

Thanks,
Amir.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 13:23     ` Amir Goldstein
@ 2026-07-08 13:44       ` Giuseppe Scrivano
  2026-07-08 14:01         ` Miklos Szeredi
  0 siblings, 1 reply; 20+ messages in thread
From: Giuseppe Scrivano @ 2026-07-08 13:44 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: Miklos Szeredi, linux-unionfs, linux-fsdevel, linux-api

Amir Goldstein <amir73il@gmail.com> writes:

> On Wed, Jul 8, 2026 at 2:31 PM Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>>
>> Miklos Szeredi <miklos@szeredi.hu> writes:
>>
>> > On Wed, 8 Jul 2026 at 12:00, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>> >>
>> >> Add two ioctls to overlay filesystem to allow userspace to retrieve
>> >> information about the overlay layers:
>> >>
>> >> OVL_IOC_OPEN_LAYER:     return an O_PATH fd to the root of a layer.
>> >>                         arg == 0 returns the upper layer (-ENOENT if
>> >>                         no upper is configured), arg >= 1 returns
>> >>                         lower layers (-ENOENT if index is out of
>> >>                         range).
>> >
>> > We could do this with a plain open() call.  Something like the magic
>> > symlinks we have under /proc/PID/fd/.   Question is where could these
>> > live...
>>
>> is there any existing user of such a mechanism?  I don't see any mount
>> specific info under /proc or /sys.
>>
>> >
>> >> OVL_IOC_GET_LAYERS_INFO: copy a struct ovl_layers_info to userspace
>> >>                         with numlower, numlowerdata, and has_upper.
>> >
>> > Isn't this info obtainable via statmount(2) already?  If not, it
>> > should be there, instead of a specialized ioctl.
>>
>> no that is not exposed by statmount and I don't see any way to export
>> file system specific data through it.  Do you've anything in mind?
>>
>> >> --- a/fs/overlayfs/ovl_entry.h
>> >> +++ b/fs/overlayfs/ovl_entry.h
>> >> @@ -35,6 +35,8 @@ struct ovl_layer {
>> >>         struct vfsmount *mnt;
>> >>         /* Trap in ovl inode cache */
>> >>         struct inode *trap;
>> >> +       /* Keeps the original fsmount file alive for OVL_IOC_OPEN_LAYER */
>> >> +       struct file *origin;
>> >
>> > Don't need to keep the file open: the only info missing is the
>> > original vfsmount, everything else is already there to reconstruct the
>> > file.
>>
>> I didn't manage to get that to work.  As soon as the userspace process
>> closes the mount fd that was passed to fsconfig, the anonymous mount
>> namespace is destroyed and dissolve_on_fput sets mnt->mnt_ns to NULL.
>>
>> So whenever I try to use this mount again from userspace, it is not
>> usable because the mount namespace is empty, causing check_mnt() to
>> fail.
>>
>> Do you have any suggestions on how to solve this problem?
>
> The suggestion was to store origin->f_path->mnt instead of storing origin file,
> because you only end up using the origin vfsmount.

the reason I am keeping the file and not just the vfsmount is that the
file is what keeps the mount namespace alive (preventing
dissolve_on_fput from fire).

Should we export open_detached_copy from fs/namespace.c?  I've not
tested it, but it might work.  Are there other ways to solve it that I
am not seeing?

Thanks,
Giuseppe


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 13:44       ` Giuseppe Scrivano
@ 2026-07-08 14:01         ` Miklos Szeredi
  2026-07-08 20:45           ` Giuseppe Scrivano
  0 siblings, 1 reply; 20+ messages in thread
From: Miklos Szeredi @ 2026-07-08 14:01 UTC (permalink / raw)
  To: Giuseppe Scrivano; +Cc: Amir Goldstein, linux-unionfs, linux-fsdevel, linux-api

On Wed, 8 Jul 2026 at 15:44, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>
> Amir Goldstein <amir73il@gmail.com> writes:
>
> > On Wed, Jul 8, 2026 at 2:31 PM Giuseppe Scrivano <gscrivan@redhat.com> wrote:
> >>
> >> Miklos Szeredi <miklos@szeredi.hu> writes:
> >>
> >> > On Wed, 8 Jul 2026 at 12:00, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
> >> >>
> >> >> Add two ioctls to overlay filesystem to allow userspace to retrieve
> >> >> information about the overlay layers:
> >> >>
> >> >> OVL_IOC_OPEN_LAYER:     return an O_PATH fd to the root of a layer.
> >> >>                         arg == 0 returns the upper layer (-ENOENT if
> >> >>                         no upper is configured), arg >= 1 returns
> >> >>                         lower layers (-ENOENT if index is out of
> >> >>                         range).
> >> >
> >> > We could do this with a plain open() call.  Something like the magic
> >> > symlinks we have under /proc/PID/fd/.   Question is where could these
> >> > live...
> >>
> >> is there any existing user of such a mechanism?  I don't see any mount
> >> specific info under /proc or /sys.
> >>
> >> >
> >> >> OVL_IOC_GET_LAYERS_INFO: copy a struct ovl_layers_info to userspace
> >> >>                         with numlower, numlowerdata, and has_upper.
> >> >
> >> > Isn't this info obtainable via statmount(2) already?  If not, it
> >> > should be there, instead of a specialized ioctl.
> >>
> >> no that is not exposed by statmount and I don't see any way to export
> >> file system specific data through it.  Do you've anything in mind?
> >>
> >> >> --- a/fs/overlayfs/ovl_entry.h
> >> >> +++ b/fs/overlayfs/ovl_entry.h
> >> >> @@ -35,6 +35,8 @@ struct ovl_layer {
> >> >>         struct vfsmount *mnt;
> >> >>         /* Trap in ovl inode cache */
> >> >>         struct inode *trap;
> >> >> +       /* Keeps the original fsmount file alive for OVL_IOC_OPEN_LAYER */
> >> >> +       struct file *origin;
> >> >
> >> > Don't need to keep the file open: the only info missing is the
> >> > original vfsmount, everything else is already there to reconstruct the
> >> > file.
> >>
> >> I didn't manage to get that to work.  As soon as the userspace process
> >> closes the mount fd that was passed to fsconfig, the anonymous mount
> >> namespace is destroyed and dissolve_on_fput sets mnt->mnt_ns to NULL.
> >>
> >> So whenever I try to use this mount again from userspace, it is not
> >> usable because the mount namespace is empty, causing check_mnt() to
> >> fail.
> >>
> >> Do you have any suggestions on how to solve this problem?
> >
> > The suggestion was to store origin->f_path->mnt instead of storing origin file,
> > because you only end up using the origin vfsmount.
>
> the reason I am keeping the file and not just the vfsmount is that the
> file is what keeps the mount namespace alive (preventing
> dissolve_on_fput from fire).
>
> Should we export open_detached_copy from fs/namespace.c?  I've not
> tested it, but it might work.  Are there other ways to solve it that I
> am not seeing?

Using an anon namespace sounds good to me, that means the original
vfsmount isn't needed at all.

Not sure if it's okay for the case where the original ns is not anon,
but we can save the vfsmount in that case if it turns out to be a
problem.

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 12:27   ` Giuseppe Scrivano
  2026-07-08 13:23     ` Amir Goldstein
@ 2026-07-08 14:08     ` Miklos Szeredi
  2026-07-08 14:31       ` Giuseppe Scrivano
  1 sibling, 1 reply; 20+ messages in thread
From: Miklos Szeredi @ 2026-07-08 14:08 UTC (permalink / raw)
  To: Giuseppe Scrivano; +Cc: linux-unionfs, linux-fsdevel, linux-api

On Wed, 8 Jul 2026 at 14:27, Giuseppe Scrivano <gscrivan@redhat.com> wrote:

> is there any existing user of such a mechanism?  I don't see any mount
> specific info under /proc or /sys.

Not yet, but I think it would be good to have one.  It's definitely a
bigger bite than adding an ioctl(), though.

> >> OVL_IOC_GET_LAYERS_INFO: copy a struct ovl_layers_info to userspace
> >>                         with numlower, numlowerdata, and has_upper.
> >
> > Isn't this info obtainable via statmount(2) already?  If not, it
> > should be there, instead of a specialized ioctl.
>

> no that is not exposed by statmount

I mean, you should be able to get that info by counting the lowerdir+,
datadir+ and upperdir options, no?

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 14:08     ` Miklos Szeredi
@ 2026-07-08 14:31       ` Giuseppe Scrivano
  2026-07-08 15:37         ` Miklos Szeredi
  0 siblings, 1 reply; 20+ messages in thread
From: Giuseppe Scrivano @ 2026-07-08 14:31 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: linux-unionfs, linux-fsdevel, linux-api, Amir Goldstein

Miklos Szeredi <miklos@szeredi.hu> writes:

> On Wed, 8 Jul 2026 at 14:27, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>
>> is there any existing user of such a mechanism?  I don't see any mount
>> specific info under /proc or /sys.
>
> Not yet, but I think it would be good to have one.  It's definitely a
> bigger bite than adding an ioctl(), though.
>
>> >> OVL_IOC_GET_LAYERS_INFO: copy a struct ovl_layers_info to userspace
>> >>                         with numlower, numlowerdata, and has_upper.
>> >
>> > Isn't this info obtainable via statmount(2) already?  If not, it
>> > should be there, instead of a specialized ioctl.
>>
>
>> no that is not exposed by statmount
>
> I mean, you should be able to get that info by counting the lowerdir+,
> datadir+ and upperdir options, no?

Amir suggested to add that functionality when I've asked for some
feedback before sending the patch here.  I am fine to drop it if this is
the consensus although I see its utility from user space.

Regards,
Giuseppe


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 14:31       ` Giuseppe Scrivano
@ 2026-07-08 15:37         ` Miklos Szeredi
  2026-07-08 15:55           ` Giuseppe Scrivano
  0 siblings, 1 reply; 20+ messages in thread
From: Miklos Szeredi @ 2026-07-08 15:37 UTC (permalink / raw)
  To: Giuseppe Scrivano; +Cc: linux-unionfs, linux-fsdevel, linux-api, Amir Goldstein

On Wed, 8 Jul 2026 at 16:32, Giuseppe Scrivano <gscrivan@redhat.com> wrote:

> Amir suggested to add that functionality when I've asked for some
> feedback before sending the patch here.  I am fine to drop it if this is
> the consensus although I see its utility from user space.

How about a completely different interface:

int get_fd_opt(const char *name, unsigned int index, unsigned int flags);

Enumerating layers would be as easy as passing an index stating from
zero and stopping when -ERANGE is received.

It would work for all filesystems that use files as options.  No more
fs specific ioctls.

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 15:37         ` Miklos Szeredi
@ 2026-07-08 15:55           ` Giuseppe Scrivano
  2026-07-08 19:01             ` Amir Goldstein
  2026-07-08 19:45             ` Miklos Szeredi
  0 siblings, 2 replies; 20+ messages in thread
From: Giuseppe Scrivano @ 2026-07-08 15:55 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: linux-unionfs, linux-fsdevel, linux-api, Amir Goldstein, Al Viro,
	Christian Brauner

Miklos Szeredi <miklos@szeredi.hu> writes:

> On Wed, 8 Jul 2026 at 16:32, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>
>> Amir suggested to add that functionality when I've asked for some
>> feedback before sending the patch here.  I am fine to drop it if this is
>> the consensus although I see its utility from user space.
>
> How about a completely different interface:
>
> int get_fd_opt(const char *name, unsigned int index, unsigned int flags);
>
> Enumerating layers would be as easy as passing an index stating from
> zero and stopping when -ERANGE is received.
>
> It would work for all filesystems that use files as options.  No more
> fs specific ioctls.

Is a new syscall really justified for such a narrow use case?

On the other hand, it would cover both ioctl's I am working on right
now.

Regards,
Giuseppe


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 15:55           ` Giuseppe Scrivano
@ 2026-07-08 19:01             ` Amir Goldstein
  2026-07-08 20:16               ` Colin Walters
  2026-07-08 20:18               ` Giuseppe Scrivano
  2026-07-08 19:45             ` Miklos Szeredi
  1 sibling, 2 replies; 20+ messages in thread
From: Amir Goldstein @ 2026-07-08 19:01 UTC (permalink / raw)
  To: Giuseppe Scrivano
  Cc: Miklos Szeredi, linux-unionfs, linux-fsdevel, linux-api, Al Viro,
	Christian Brauner, Gao Xiang, linux-erofs mailing list

On Wed, Jul 8, 2026 at 5:55 PM Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>
> Miklos Szeredi <miklos@szeredi.hu> writes:
>
> > On Wed, 8 Jul 2026 at 16:32, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
> >
> >> Amir suggested to add that functionality when I've asked for some
> >> feedback before sending the patch here.  I am fine to drop it if this is
> >> the consensus although I see its utility from user space.

I was thinking that getting the number of layers or info would be
a good idea to complement getting a layer fd.

I agree that the same information is probably available via statmount
by parsing the upperdir/lowerdir/datadir mount options.

> >
> > How about a completely different interface:
> >
> > int get_fd_opt(const char *name, unsigned int index, unsigned int flags);
> >
> > Enumerating layers would be as easy as passing an index stating from
> > zero and stopping when -ERANGE is received.
> >
> > It would work for all filesystems that use files as options.  No more
> > fs specific ioctls.
>
> Is a new syscall really justified for such a narrow use case?
>

I feel the same way.

Giuseppe,

Could you add some high level context in this thread on why you need
this functionality.
I think it's this composefs-rs work. right?
https://github.com/giuseppe/composefs-rs/commits/reuse-mounts-and-prevent-gc-overlay/

I must say this seems a bit upside down to me.

If you want to keep a pool of mounted erofs images, you could do that
in userspace -
create a service that indexes mounted erofs images by unique mount point paths.
Then you can introspect the overlayfs mount options referring to those
mount points.

Going through the kernel to get an fd and reuse that fd for a new
overlayfs mount
sounds like a strange way of accomplishing this.

If the overlayfs mounter is unprivileged, it would have to go through
systemd-mountfsd
to request a mount of erofs trusted image, right?

Can't the same service provide the "is_image_mounted" query which provides
the mount path?

I am not against introspection of overlayfs, but I'd like to understand
the use cases before finalizing the uapi.

Thanks,
Amir.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 15:55           ` Giuseppe Scrivano
  2026-07-08 19:01             ` Amir Goldstein
@ 2026-07-08 19:45             ` Miklos Szeredi
  2026-07-08 20:35               ` Giuseppe Scrivano
  2026-07-09 14:32               ` Amir Goldstein
  1 sibling, 2 replies; 20+ messages in thread
From: Miklos Szeredi @ 2026-07-08 19:45 UTC (permalink / raw)
  To: Giuseppe Scrivano
  Cc: linux-unionfs, linux-fsdevel, linux-api, Amir Goldstein, Al Viro,
	Christian Brauner

On Wed, 8 Jul 2026 at 17:55, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>
> Miklos Szeredi <miklos@szeredi.hu> writes:
>
> > On Wed, 8 Jul 2026 at 16:32, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
> >
> >> Amir suggested to add that functionality when I've asked for some
> >> feedback before sending the patch here.  I am fine to drop it if this is
> >> the consensus although I see its utility from user space.
> >
> > How about a completely different interface:
> >
> > int get_fd_opt(const char *name, unsigned int index, unsigned int flags);
> >
> > Enumerating layers would be as easy as passing an index stating from
> > zero and stopping when -ERANGE is received.
> >
> > It would work for all filesystems that use files as options.  No more
> > fs specific ioctls.
>
> Is a new syscall really justified for such a narrow use case?

That's the reason I advocate pseudo fs based solutions.  Let's see, we
had a proposal to use openat(), something. like:

openat(base_fd, "mount/options/lowerdir+/0", O_ALT | O_PATH);

Meaning that O_ALT switches to an alternative/meta namespace that is
based on the given fd and in that meta namespace the tree under mount/
represents the attributes of the mount that base_fd is on.

See this post from Linus as well:

  https://lore.kernel.org/all/CAHk-=wjzLmMRf=QG-n+1HnxWCx4KTQn9+OhVvUSJ=ZCQd6Y1WA@mail.gmail.com/

The statmount api took a different route, but for getting an O_PATH
file this would be a very natural interface without added syscalls.

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 19:01             ` Amir Goldstein
@ 2026-07-08 20:16               ` Colin Walters
  2026-07-08 20:18               ` Giuseppe Scrivano
  1 sibling, 0 replies; 20+ messages in thread
From: Colin Walters @ 2026-07-08 20:16 UTC (permalink / raw)
  To: Amir Goldstein, Giuseppe Scrivano
  Cc: Miklos Szeredi, linux-unionfs@vger.kernel.org,
	linux-fsdevel@vger.kernel.org, linux-api, Al Viro,
	Christian Brauner, Gao Xiang, linux-erofs mailing list



On Wed, Jul 8, 2026, at 3:01 PM, Amir Goldstein wrote:

> If you want to keep a pool of mounted erofs images, you could do that
> in userspace -
> create a service that indexes mounted erofs images by unique mount point paths.

You're right that it’d be possible to do this in user space. 

However, overlayfs is used by many things (it’s a powerful “Swiss army knife”!) and this ability to reliably introspect its components is I think generally useful.

For example: https://github.com/systemd/systemd/issues/35017#issuecomment-2457333218

Various tools want to know the backing filesystem(s) and/or block devices thereof, and if we don’t have something like this in the general case every overlayfs user would need to agree on a scheme to store this data out of band - and manage its lifecycle as mounts change and deal with where that data is stored with respect to mount namespaces etc.

Even if we had this API, would it be better to have a user space cache server for the original use case here? Maybe. I could personally go either way.

But the introspection I think really would be generally useful and there are code bases (in systemd and in composefs at least) that would start using it (with fallback for old kernels) for at least that use case right away.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 19:01             ` Amir Goldstein
  2026-07-08 20:16               ` Colin Walters
@ 2026-07-08 20:18               ` Giuseppe Scrivano
  1 sibling, 0 replies; 20+ messages in thread
From: Giuseppe Scrivano @ 2026-07-08 20:18 UTC (permalink / raw)
  To: Amir Goldstein
  Cc: Miklos Szeredi, linux-unionfs, linux-fsdevel, linux-api, Al Viro,
	Christian Brauner, Gao Xiang, linux-erofs mailing list

Amir Goldstein <amir73il@gmail.com> writes:

> On Wed, Jul 8, 2026 at 5:55 PM Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>>
>> Miklos Szeredi <miklos@szeredi.hu> writes:
>>
>> > On Wed, 8 Jul 2026 at 16:32, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>> >
>> >> Amir suggested to add that functionality when I've asked for some
>> >> feedback before sending the patch here.  I am fine to drop it if this is
>> >> the consensus although I see its utility from user space.
>
> I was thinking that getting the number of layers or info would be
> a good idea to complement getting a layer fd.
>
> I agree that the same information is probably available via statmount
> by parsing the upperdir/lowerdir/datadir mount options.
>
>> >
>> > How about a completely different interface:
>> >
>> > int get_fd_opt(const char *name, unsigned int index, unsigned int flags);
>> >
>> > Enumerating layers would be as easy as passing an index stating from
>> > zero and stopping when -ERANGE is received.
>> >
>> > It would work for all filesystems that use files as options.  No more
>> > fs specific ioctls.
>>
>> Is a new syscall really justified for such a narrow use case?
>>
>
> I feel the same way.
>
> Giuseppe,
>
> Could you add some high level context in this thread on why you need
> this functionality.
> I think it's this composefs-rs work. right?
> https://github.com/giuseppe/composefs-rs/commits/reuse-mounts-and-prevent-gc-overlay/
>
> I must say this seems a bit upside down to me.
>
> If you want to keep a pool of mounted erofs images, you could do that
> in userspace -
> create a service that indexes mounted erofs images by unique mount point paths.
> Then you can introspect the overlayfs mount options referring to those
> mount points.

A first issue is that the mount options won't have this information
anymore, as we use /proc/self/fd/$i paths as lower dirs so we are sure
the fd points exactly to the file we have measured its fs-verity digest
before using it.

I know this can be achieved with a system daemon, but do we really need
one if this information is already known to the kernel?

Combined with listmount/statmount for discovery and fs-verity for
validation, the entire mechanism is stateless from userspace.

More in general we need a way to introspect overlay mounts to know where
they are pointing to since paths can be hidden using /proc/*/fd
symlinks, or files get replaced.

Another similar request:
https://github.com/systemd/systemd/issues/35017#issuecomment-2457333218

> Going through the kernel to get an fd and reuse that fd for a new
> overlayfs mount
> sounds like a strange way of accomplishing this.
>
> If the overlayfs mounter is unprivileged, it would have to go through
> systemd-mountfsd
> to request a mount of erofs trusted image, right?

off-topic but for now we are considering FUSE to deal with mounting
EROFS as it would serve only the metadata anyway in a composefs setup.

Regards,
Giuseppe

> Can't the same service provide the "is_image_mounted" query which provides
> the mount path?
>
> I am not against introspection of overlayfs, but I'd like to understand
> the use cases before finalizing the uapi.
>
> Thanks,
> Amir.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 19:45             ` Miklos Szeredi
@ 2026-07-08 20:35               ` Giuseppe Scrivano
  2026-07-09  6:11                 ` Miklos Szeredi
  2026-07-09 14:32               ` Amir Goldstein
  1 sibling, 1 reply; 20+ messages in thread
From: Giuseppe Scrivano @ 2026-07-08 20:35 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: linux-unionfs, linux-fsdevel, linux-api, Amir Goldstein, Al Viro,
	Christian Brauner

Miklos Szeredi <miklos@szeredi.hu> writes:

> On Wed, 8 Jul 2026 at 17:55, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>>
>> Miklos Szeredi <miklos@szeredi.hu> writes:
>>
>> > On Wed, 8 Jul 2026 at 16:32, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>> >
>> >> Amir suggested to add that functionality when I've asked for some
>> >> feedback before sending the patch here.  I am fine to drop it if this is
>> >> the consensus although I see its utility from user space.
>> >
>> > How about a completely different interface:
>> >
>> > int get_fd_opt(const char *name, unsigned int index, unsigned int flags);
>> >
>> > Enumerating layers would be as easy as passing an index stating from
>> > zero and stopping when -ERANGE is received.
>> >
>> > It would work for all filesystems that use files as options.  No more
>> > fs specific ioctls.
>>
>> Is a new syscall really justified for such a narrow use case?
>
> That's the reason I advocate pseudo fs based solutions.  Let's see, we
> had a proposal to use openat(), something. like:
>
> openat(base_fd, "mount/options/lowerdir+/0", O_ALT | O_PATH);
>
> Meaning that O_ALT switches to an alternative/meta namespace that is
> based on the given fd and in that meta namespace the tree under mount/
> represents the attributes of the mount that base_fd is on.
>
> See this post from Linus as well:
>
>   https://lore.kernel.org/all/CAHk-=wjzLmMRf=QG-n+1HnxWCx4KTQn9+OhVvUSJ=ZCQd6Y1WA@mail.gmail.com/
>
> The statmount api took a different route, but for getting an O_PATH
> file this would be a very natural interface without added syscalls.

I don't argue against such an API, I only argue that I am probably not
the best person to drive such a significant change :-)

Would you be OK with the ioctl as a solution that works today, and
duplicate it when an alternative API materializes?

Thanks,
Giuseppe


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 14:01         ` Miklos Szeredi
@ 2026-07-08 20:45           ` Giuseppe Scrivano
  0 siblings, 0 replies; 20+ messages in thread
From: Giuseppe Scrivano @ 2026-07-08 20:45 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Amir Goldstein, linux-unionfs, linux-fsdevel, linux-api

Miklos Szeredi <miklos@szeredi.hu> writes:

> On Wed, 8 Jul 2026 at 15:44, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>>
>> Amir Goldstein <amir73il@gmail.com> writes:
>>
>> > On Wed, Jul 8, 2026 at 2:31 PM Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>> >>
>> >> Miklos Szeredi <miklos@szeredi.hu> writes:
>> >>
>> >> > On Wed, 8 Jul 2026 at 12:00, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
>> >> >>
>> >> >> Add two ioctls to overlay filesystem to allow userspace to retrieve
>> >> >> information about the overlay layers:
>> >> >>
>> >> >> OVL_IOC_OPEN_LAYER:     return an O_PATH fd to the root of a layer.
>> >> >>                         arg == 0 returns the upper layer (-ENOENT if
>> >> >>                         no upper is configured), arg >= 1 returns
>> >> >>                         lower layers (-ENOENT if index is out of
>> >> >>                         range).
>> >> >
>> >> > We could do this with a plain open() call.  Something like the magic
>> >> > symlinks we have under /proc/PID/fd/.   Question is where could these
>> >> > live...
>> >>
>> >> is there any existing user of such a mechanism?  I don't see any mount
>> >> specific info under /proc or /sys.
>> >>
>> >> >
>> >> >> OVL_IOC_GET_LAYERS_INFO: copy a struct ovl_layers_info to userspace
>> >> >>                         with numlower, numlowerdata, and has_upper.
>> >> >
>> >> > Isn't this info obtainable via statmount(2) already?  If not, it
>> >> > should be there, instead of a specialized ioctl.
>> >>
>> >> no that is not exposed by statmount and I don't see any way to export
>> >> file system specific data through it.  Do you've anything in mind?
>> >>
>> >> >> --- a/fs/overlayfs/ovl_entry.h
>> >> >> +++ b/fs/overlayfs/ovl_entry.h
>> >> >> @@ -35,6 +35,8 @@ struct ovl_layer {
>> >> >>         struct vfsmount *mnt;
>> >> >>         /* Trap in ovl inode cache */
>> >> >>         struct inode *trap;
>> >> >> +       /* Keeps the original fsmount file alive for OVL_IOC_OPEN_LAYER */
>> >> >> +       struct file *origin;
>> >> >
>> >> > Don't need to keep the file open: the only info missing is the
>> >> > original vfsmount, everything else is already there to reconstruct the
>> >> > file.
>> >>
>> >> I didn't manage to get that to work.  As soon as the userspace process
>> >> closes the mount fd that was passed to fsconfig, the anonymous mount
>> >> namespace is destroyed and dissolve_on_fput sets mnt->mnt_ns to NULL.
>> >>
>> >> So whenever I try to use this mount again from userspace, it is not
>> >> usable because the mount namespace is empty, causing check_mnt() to
>> >> fail.
>> >>
>> >> Do you have any suggestions on how to solve this problem?
>> >
>> > The suggestion was to store origin->f_path->mnt instead of storing origin file,
>> > because you only end up using the origin vfsmount.
>>
>> the reason I am keeping the file and not just the vfsmount is that the
>> file is what keeps the mount namespace alive (preventing
>> dissolve_on_fput from fire).
>>
>> Should we export open_detached_copy from fs/namespace.c?  I've not
>> tested it, but it might work.  Are there other ways to solve it that I
>> am not seeing?
>
> Using an anon namespace sounds good to me, that means the original
> vfsmount isn't needed at all.
>
> Not sure if it's okay for the case where the original ns is not anon,
> but we can save the vfsmount in that case if it turns out to be a
> problem.
>
> Thanks,
> Miklos

for this to work, I need something like:

diff --git a/fs/namespace.c b/fs/namespace.c
index 3d5cd5bf3b05..138d15ab37ef 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3091,6 +3091,52 @@ static struct file *open_detached_copy(struct path *path, unsigned int flags)
 	return file;
 }
 
+struct file *open_detached_copy_internal(struct path *path)
+{
+	struct mnt_namespace *ns, *mnt_ns = current->nsproxy->mnt_ns;
+	struct mount *mnt;
+	struct file *file;
+
+	ns = alloc_mnt_ns(mnt_ns->user_ns, true);
+	if (IS_ERR(ns))
+		return ERR_CAST(ns);
+
+	guard(namespace_excl)();
+
+	mnt = clone_mnt(real_mount(path->mnt), path->dentry,
+			CL_COPY_MNT_NS_FILE);
+	if (IS_ERR(mnt)) {
+		free_mnt_ns(ns);
+		return ERR_CAST(mnt);
+	}
+
+	mnt_add_to_ns(ns, mnt);
+	ns->nr_mounts++;
+	ns->root = mnt;
+
+	mntput(path->mnt);
+	path->mnt = mntget(&mnt->mnt);
+	file = dentry_open(path, O_PATH, current_cred());
+	if (IS_ERR(file))
+		dissolve_on_fput(path->mnt);
+	else
+		file->f_mode |= FMODE_NEED_UNMOUNT;
+	return file;
+}
+EXPORT_SYMBOL_GPL(open_detached_copy_internal);
+
 enum mount_copy_flags_t {
 	MOUNT_COPY_RECURSIVE    = (1 << 0),
 	MOUNT_COPY_NEW		= (1 << 1),

is this acceptable?

Regards,
Giuseppe


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 20:35               ` Giuseppe Scrivano
@ 2026-07-09  6:11                 ` Miklos Szeredi
  0 siblings, 0 replies; 20+ messages in thread
From: Miklos Szeredi @ 2026-07-09  6:11 UTC (permalink / raw)
  To: Giuseppe Scrivano
  Cc: linux-unionfs, linux-fsdevel, linux-api, Amir Goldstein, Al Viro,
	Christian Brauner

On Wed, 8 Jul 2026 at 22:35, Giuseppe Scrivano <gscrivan@redhat.com> wrote:

> Would you be OK with the ioctl as a solution that works today, and
> duplicate it when an alternative API materializes?

Let me have a go at the pseudo fs interface first.  I can probably do
a quick 'n dirty prototype within a couple of days and see what
reaction it gets...

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-08 19:45             ` Miklos Szeredi
  2026-07-08 20:35               ` Giuseppe Scrivano
@ 2026-07-09 14:32               ` Amir Goldstein
  2026-07-10 18:23                 ` Miklos Szeredi
  1 sibling, 1 reply; 20+ messages in thread
From: Amir Goldstein @ 2026-07-09 14:32 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: Giuseppe Scrivano, linux-unionfs, linux-fsdevel, linux-api,
	Al Viro, Christian Brauner, Daan De Meyer

On Wed, Jul 8, 2026 at 9:45 PM Miklos Szeredi <miklos@szeredi.hu> wrote:
>
> On Wed, 8 Jul 2026 at 17:55, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
> >
> > Miklos Szeredi <miklos@szeredi.hu> writes:
> >
> > > On Wed, 8 Jul 2026 at 16:32, Giuseppe Scrivano <gscrivan@redhat.com> wrote:
> > >
> > >> Amir suggested to add that functionality when I've asked for some
> > >> feedback before sending the patch here.  I am fine to drop it if this is
> > >> the consensus although I see its utility from user space.
> > >
> > > How about a completely different interface:
> > >
> > > int get_fd_opt(const char *name, unsigned int index, unsigned int flags);
> > >
> > > Enumerating layers would be as easy as passing an index stating from
> > > zero and stopping when -ERANGE is received.
> > >
> > > It would work for all filesystems that use files as options.  No more
> > > fs specific ioctls.
> >
> > Is a new syscall really justified for such a narrow use case?
>
> That's the reason I advocate pseudo fs based solutions.  Let's see, we
> had a proposal to use openat(), something. like:
>
> openat(base_fd, "mount/options/lowerdir+/0", O_ALT | O_PATH);
>

Ack for this, but please don't use mount/options/... it's a bit ugly
because most mount options are not opan-able.

Please stick to something logical like "fs/layers/N" corresponding to
ovl_fs::layers, where layer 0 is reserved for upper.
We could also support opening by aliases fs/layers/upper->0 etc,
but no rush IMO.

What I am contemplating is whether we should implement
introspection of the ovl_entry stack for merge dirs in addition or instead
introspection of fs/layers.

IIRC, the root dir stack does NOT hold references to lowerdata dirs,
so support for "fs/layers/N" is still needed.

For directories we could implement "real/0..N" with aliases
real/upper->0 real/origin->1.

For a regular file we could have constant aliases real/upper->0
real/lower->1 real/lowerdata->2 and/or dynamic aliases
real/data->{0,1,2}, real/metadata->{0,1}, real/origin->{0,1}.

Those could be used to implement "revert to origin".
Specifically, I think Daan asked for it during the last LSFMM.
Although I don't think we currently store the original lowerdata
in ovl_entry when lookup is done post data copy up.

Thanks,
Amir.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] ovl: add ioctls to retrieve layer file descriptors
  2026-07-09 14:32               ` Amir Goldstein
@ 2026-07-10 18:23                 ` Miklos Szeredi
  0 siblings, 0 replies; 20+ messages in thread
From: Miklos Szeredi @ 2026-07-10 18:23 UTC (permalink / raw)
  To: Amir Goldstein
  Cc: Giuseppe Scrivano, linux-unionfs, linux-fsdevel, linux-api,
	Al Viro, Christian Brauner, Daan De Meyer

On Thu, 9 Jul 2026 at 16:32, Amir Goldstein <amir73il@gmail.com> wrote:

> Ack for this, but please don't use mount/options/... it's a bit ugly
> because most mount options are not opan-able.

True, but I was thinking of doing this as a reverse fsconfig() thing.

> Please stick to something logical like "fs/layers/N" corresponding to
> ovl_fs::layers, where layer 0 is reserved for upper.
> We could also support opening by aliases fs/layers/upper->0 etc,
> but no rush IMO.

Layer numbering has been internal to overlayfs to date.  I'd prefer to
keep the layer enumeration that is external, which is the mount option
interface.  Works for EROFS as well.

> What I am contemplating is whether we should implement
> introspection of the ovl_entry stack for merge dirs in addition or instead
> introspection of fs/layers.

Interesting.

> IIRC, the root dir stack does NOT hold references to lowerdata dirs,
> so support for "fs/layers/N" is still needed.

So let's just stick with the per-superblock layering for now, which is
reflected in the mount options.

>
> For directories we could implement "real/0..N" with aliases
> real/upper->0 real/origin->1.
>
> For a regular file we could have constant aliases real/upper->0
> real/lower->1 real/lowerdata->2 and/or dynamic aliases
> real/data->{0,1,2}, real/metadata->{0,1}, real/origin->{0,1}.
>
> Those could be used to implement "revert to origin".
> Specifically, I think Daan asked for it during the last LSFMM.
> Although I don't think we currently store the original lowerdata
> in ovl_entry when lookup is done post data copy up.

I'm trying to focus on the "return an O_PATH descriptor for stacked
layers" for now.  It avoids having to deal with opening files or
directories within the O_ALT namespace, since magic symlink following
is used.

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2026-07-10 18:23 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-08  9:58 [PATCH] ovl: add ioctls to retrieve layer file descriptors Giuseppe Scrivano
2026-07-08 10:24 ` Miklos Szeredi
2026-07-08 12:27   ` Giuseppe Scrivano
2026-07-08 13:23     ` Amir Goldstein
2026-07-08 13:44       ` Giuseppe Scrivano
2026-07-08 14:01         ` Miklos Szeredi
2026-07-08 20:45           ` Giuseppe Scrivano
2026-07-08 14:08     ` Miklos Szeredi
2026-07-08 14:31       ` Giuseppe Scrivano
2026-07-08 15:37         ` Miklos Szeredi
2026-07-08 15:55           ` Giuseppe Scrivano
2026-07-08 19:01             ` Amir Goldstein
2026-07-08 20:16               ` Colin Walters
2026-07-08 20:18               ` Giuseppe Scrivano
2026-07-08 19:45             ` Miklos Szeredi
2026-07-08 20:35               ` Giuseppe Scrivano
2026-07-09  6:11                 ` Miklos Szeredi
2026-07-09 14:32               ` Amir Goldstein
2026-07-10 18:23                 ` Miklos Szeredi
2026-07-08 10:40 ` Amir Goldstein

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.