diff mbox series

[RFC] overlayfs: add OVL_IOC_GETINFOFD ioctl that opens ovlinfofd

Message ID 20201005170227.11340-1-alexander.mikhalitsyn@virtuozzo.com (mailing list archive)
State New, archived
Headers show
Series [RFC] overlayfs: add OVL_IOC_GETINFOFD ioctl that opens ovlinfofd | expand

Commit Message

Alexander Mikhalitsyn Oct. 5, 2020, 5:02 p.m. UTC
Second variant of possible interface to get source-dirs fhandles from
userspace. OVL_IOC_GETINFOFD ioctls opens special [ovlinfofd] descriptor
which is really just seq_file. When read from this seq_file we will get
something like this:
===
numlower: 2
L fhandle-bytes:c fhandle-type:1 f_handle:9685a2160200000000000000
L fhandle-bytes:c fhandle-type:1 f_handle:c74cd5c10300000000000000
U fhandle-bytes:c fhandle-type:1 f_handle:e45842640400000000000000
W fhandle-bytes:c fhandle-type:1 f_handle:d393374d0500000000000000
===

Cc: Amir Goldstein <amir73il@gmail.com>
Cc: Andrei Vagin <avagin@gmail.com>
Cc: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Cc: Miklos Szeredi <miklos@szeredi.hu>
Cc: David Howells <dhowells@redhat.com>
Cc: linux-unionfs@vger.kernel.org
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
---
 fs/overlayfs/readdir.c | 171 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 171 insertions(+)

Comments

Randy Dunlap Oct. 5, 2020, 5:08 p.m. UTC | #1
On 10/5/20 10:02 AM, Alexander Mikhalitsyn wrote:
>  #define	OVL_IOC_GETLWRFHNDLSNUM			_IO('o', 1)
>  // DISCUSS: what if MAX_HANDLE_SZ will change?
>  #define	OVL_IOC_GETLWRFHNDL			_IOR('o', 2, struct ovl_mnt_opt_fh)
>  #define	OVL_IOC_GETUPPRFHNDL			_IOR('o', 3, struct ovl_mnt_opt_fh)
>  #define	OVL_IOC_GETWRKFHNDL			_IOR('o', 4, struct ovl_mnt_opt_fh)
> +#define	OVL_IOC_GETINFOFD			_IO('o', 5)

Hi,

Quoting (repeating) from
https://lore.kernel.org/lkml/9cd0e9d1-f124-3f2d-86e6-e6e96a1ccb1e@infradead.org/:

This needs to have Documentation/userspace-api/ioctl/ioctl-number.rst
updated also.

...

Are you waiting until it's past RFC stage?

thanks.
Alexander Mikhalitsyn Oct. 5, 2020, 5:12 p.m. UTC | #2
On Mon, 5 Oct 2020 10:08:42 -0700
Randy Dunlap <rdunlap@infradead.org> wrote:

> On 10/5/20 10:02 AM, Alexander Mikhalitsyn wrote:
> >  #define	OVL_IOC_GETLWRFHNDLSNUM			_IO('o', 1)
> >  // DISCUSS: what if MAX_HANDLE_SZ will change?
> >  #define	OVL_IOC_GETLWRFHNDL			_IOR('o', 2, struct ovl_mnt_opt_fh)
> >  #define	OVL_IOC_GETUPPRFHNDL			_IOR('o', 3, struct ovl_mnt_opt_fh)
> >  #define	OVL_IOC_GETWRKFHNDL			_IOR('o', 4, struct ovl_mnt_opt_fh)
> > +#define	OVL_IOC_GETINFOFD			_IO('o', 5)
> 
> Hi,
> 
> Quoting (repeating) from
> https://lore.kernel.org/lkml/9cd0e9d1-f124-3f2d-86e6-e6e96a1ccb1e@infradead.org/:
> 
> This needs to have Documentation/userspace-api/ioctl/ioctl-number.rst
> updated also.
> 
> ...
> 
> Are you waiting until it's past RFC stage?
> 
> thanks.
> -- 
> ~Randy
> 

Hi,

thank you! I will prepare this change too when we
decide which ioctls to add. ;)

Regards,
Alex.
Amir Goldstein Oct. 5, 2020, 5:22 p.m. UTC | #3
On Mon, Oct 5, 2020 at 8:13 PM Alexander Mikhalitsyn
<alexander.mikhalitsyn@virtuozzo.com> wrote:
>
> On Mon, 5 Oct 2020 10:08:42 -0700
> Randy Dunlap <rdunlap@infradead.org> wrote:
>
> > On 10/5/20 10:02 AM, Alexander Mikhalitsyn wrote:
> > >  #define    OVL_IOC_GETLWRFHNDLSNUM                 _IO('o', 1)
> > >  // DISCUSS: what if MAX_HANDLE_SZ will change?
> > >  #define    OVL_IOC_GETLWRFHNDL                     _IOR('o', 2, struct ovl_mnt_opt_fh)
> > >  #define    OVL_IOC_GETUPPRFHNDL                    _IOR('o', 3, struct ovl_mnt_opt_fh)
> > >  #define    OVL_IOC_GETWRKFHNDL                     _IOR('o', 4, struct ovl_mnt_opt_fh)
> > > +#define    OVL_IOC_GETINFOFD                       _IO('o', 5)
> >
> > Hi,
> >
> > Quoting (repeating) from
> > https://lore.kernel.org/lkml/9cd0e9d1-f124-3f2d-86e6-e6e96a1ccb1e@infradead.org/:
> >
> > This needs to have Documentation/userspace-api/ioctl/ioctl-number.rst
> > updated also.
> >
> > ...
> >
> > Are you waiting until it's past RFC stage?
> >
> > thanks.
> > --
> > ~Randy
> >
>
> Hi,
>
> thank you! I will prepare this change too when we
> decide which ioctls to add. ;)
>

Or... don't do ioctls and avoid the ABI headaches.
If you are going to expose a seqfile I think it would be much prefered
to do a /sys/fs/overlay/instance/<device minor>/layes file.

But that's just my opinion.

Thanks,
Amir.
Alexander Mikhalitsyn Oct. 5, 2020, 7:39 p.m. UTC | #4
On Mon, 5 Oct 2020 20:22:47 +0300
Amir Goldstein <amir73il@gmail.com> wrote:

> On Mon, Oct 5, 2020 at 8:13 PM Alexander Mikhalitsyn
> <alexander.mikhalitsyn@virtuozzo.com> wrote:
> >
> > On Mon, 5 Oct 2020 10:08:42 -0700
> > Randy Dunlap <rdunlap@infradead.org> wrote:
> >
> > > On 10/5/20 10:02 AM, Alexander Mikhalitsyn wrote:
> > > >  #define    OVL_IOC_GETLWRFHNDLSNUM                 _IO('o', 1)
> > > >  // DISCUSS: what if MAX_HANDLE_SZ will change?
> > > >  #define    OVL_IOC_GETLWRFHNDL                     _IOR('o', 2, struct ovl_mnt_opt_fh)
> > > >  #define    OVL_IOC_GETUPPRFHNDL                    _IOR('o', 3, struct ovl_mnt_opt_fh)
> > > >  #define    OVL_IOC_GETWRKFHNDL                     _IOR('o', 4, struct ovl_mnt_opt_fh)
> > > > +#define    OVL_IOC_GETINFOFD                       _IO('o', 5)
> > >
> > > Hi,
> > >
> > > Quoting (repeating) from
> > > https://lore.kernel.org/lkml/9cd0e9d1-f124-3f2d-86e6-e6e96a1ccb1e@infradead.org/:
> > >
> > > This needs to have Documentation/userspace-api/ioctl/ioctl-number.rst
> > > updated also.
> > >
> > > ...
> > >
> > > Are you waiting until it's past RFC stage?
> > >
> > > thanks.
> > > --
> > > ~Randy
> > >
> >
> > Hi,
> >
> > thank you! I will prepare this change too when we
> > decide which ioctls to add. ;)
> >
> 
> Or... don't do ioctls and avoid the ABI headaches.
> If you are going to expose a seqfile I think it would be much prefered
> to do a /sys/fs/overlay/instance/<device minor>/layes file.
> 
> But that's just my opinion.
> 
> Thanks,
> Amir.

Hi!

Oh, yes, it's just another one choice for us ;)
I decided to create ioctl which opens fd for transferring
data about overlayfs.
Sure, let's look on sys fs. I will dive into it!

Thanks

Regards,
Alex.
Miklos Szeredi Oct. 6, 2020, 9:54 a.m. UTC | #5
On Mon, Oct 5, 2020 at 9:40 PM Alexander Mikhalitsyn
<alexander.mikhalitsyn@virtuozzo.com> wrote:

> Oh, yes, it's just another one choice for us ;)
> I decided to create ioctl which opens fd for transferring
> data about overlayfs.
> Sure, let's look on sys fs. I will dive into it!

Or maybe use fsinfo(2) or whatever it's going to be called?

That one seems stuck at the moment, but having a clear set of use
cases can possibly help move it forward.

Thanks,
Miklos
diff mbox series

Patch

diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 12ee043d2b3a..60c3c47a6b3e 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -14,6 +14,9 @@ 
 #include <linux/cred.h>
 #include <linux/ratelimit.h>
 #include <linux/exportfs.h>
+#include <linux/anon_inodes.h>
+#include <linux/seq_file.h>
+#include <linux/syscalls.h>
 #include "overlayfs.h"
 
 struct ovl_cache_entry {
@@ -1067,11 +1070,175 @@  static long ovl_ioctl_get_work_fhandle(struct super_block *sb,
 	return __ovl_ioctl_get_fhandle(ofs->workbasedir, arg);
 }
 
+static int ovlinfofd_release(struct inode *inode, struct file *file)
+{
+	printk("ovlinfofd_release\n");
+	return single_release(inode, file);
+}
+
+#ifdef CONFIG_PROC_FS
+static void ovlinfofd_show_fdinfo(struct seq_file *m, struct file *f)
+{
+	/* TODO */
+}
+#endif
+
+static const struct file_operations ovlinfofd_fops = {
+	.owner		= THIS_MODULE,
+#ifdef CONFIG_PROC_FS
+	.show_fdinfo	= ovlinfofd_show_fdinfo,
+#endif
+	.release	= ovlinfofd_release,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+};
+
+static long __ovl_ioctl_show_dentry_fhandle(struct seq_file *s,
+					    const char *prefix,
+					    struct dentry *origin)
+{
+	struct ovl_mnt_opt_fh *fh;
+	int ret = 0, i;
+
+	fh = __ovl_encode_mnt_opt_fh(origin);
+	if (IS_ERR(fh))
+		return PTR_ERR(fh);
+
+	seq_printf(s, "%s fhandle-bytes:%x fhandle-type:%x f_handle:",
+		   prefix, fh->fh.handle_bytes, fh->fh.handle_type);
+
+	for (i = 0; i < fh->fh.handle_bytes; i++)
+		seq_printf(s, "%02x", (int)fh->fh.f_handle[i]);
+
+	seq_putc(s, '\n');
+
+	kfree(fh);
+	return ret;
+}
+
+static long ovl_ioctl_show_lower_fhandle(struct seq_file *s,
+					 unsigned long arg)
+{
+	struct super_block *sb = s->private;
+	struct ovl_entry *oe = sb->s_root->d_fsdata;
+	struct dentry *origin;
+
+	if (arg >= oe->numlower)
+		return -EINVAL;
+
+	origin = oe->lowerstack[arg].dentry;
+
+	return __ovl_ioctl_show_dentry_fhandle(s, "L", origin);
+}
+
+static long ovl_ioctl_show_upper_fhandle(struct seq_file *s)
+{
+	struct super_block *sb = s->private;
+	struct ovl_fs *ofs = sb->s_fs_info;
+	struct dentry *origin;
+
+	if (!ofs->config.upperdir)
+		return -EINVAL;
+
+	origin = OVL_I(d_inode(sb->s_root))->__upperdentry;
+
+	return __ovl_ioctl_show_dentry_fhandle(s, "U", origin);
+}
+
+static long ovl_ioctl_show_work_fhandle(struct seq_file *s)
+{
+	struct super_block *sb = s->private;
+	struct ovl_fs *ofs = sb->s_fs_info;
+
+	if (!ofs->config.upperdir)
+		return -EINVAL;
+
+	return __ovl_ioctl_show_dentry_fhandle(s, "W", ofs->workbasedir);
+}
+
+static int ovlinfofd_show(struct seq_file *s, void *unused)
+{
+	struct super_block *sb = s->private;
+	struct ovl_entry *oe = sb->s_root->d_fsdata;
+	int i;
+
+	printk("ovlinfofd_show\n");
+
+	seq_printf(s, "numlower: %d\n", oe->numlower);
+
+	for (i = 0; i < oe->numlower; i++)
+		ovl_ioctl_show_lower_fhandle(s, i);
+	ovl_ioctl_show_upper_fhandle(s);
+	ovl_ioctl_show_work_fhandle(s);
+
+	return 0;
+}
+
+static long ovl_ioctl_get_info_fd(struct super_block *sb,
+				  unsigned long arg)
+{
+	struct ovl_fs *ofs = sb->s_fs_info;
+	struct ovl_entry *oe = sb->s_root->d_fsdata;
+	int err, ufd, flags = arg;
+	struct fd f;
+
+	if (flags & ~(O_CLOEXEC))
+		return -EINVAL;
+
+	/* FIXME Comment taken from signalfd.c. Need to think about this.
+	 * When we call this, the initialization must be complete, since
+	 * anon_inode_getfd() will install the fd.
+	 */
+	ufd = anon_inode_getfd("[ovlinfofd]", &ovlinfofd_fops, NULL,
+				O_RDONLY | (flags & (O_CLOEXEC)));
+	if (ufd < 0)
+		return ufd;
+
+	f = fdget(ufd);
+	if (!f.file) {
+		err = -EBADF;
+		goto err_close;
+	}
+
+	/*
+	 * It's good to have some good guess of seq_file buffer size
+	 * from start because if we will just use single_open() function
+	 * then we will make several seq_file overflows and .show callback
+	 * will be called several times. It's very bad for performance.
+	 *
+	 * Guess is very simple: we show fhandles as hex string. So,
+	 * all that we need is take MAX_HANDLE_SZ * 2 and multiply by
+	 * number of overlayfs mount source-dirs.
+	 */
+	err = single_open_size(f.file, ovlinfofd_show, sb,
+			       MAX_HANDLE_SZ * 2 *
+			       (oe->numlower + 2 * !!ofs->config.upperdir));
+	if (err)
+		goto err_fdput;
+
+	/*
+	 * We doing tricky things by combining anon_inode_getfd with seq_files,
+	 * so, it's better to check that all fine with fops after single_open_size
+	 * call.
+	 */
+	WARN_ON(f.file->f_op != &ovlinfofd_fops);
+	fdput(f);
+
+	return ufd;
+
+err_fdput:
+	fdput(f);
+err_close:
+	ksys_close(ufd);
+	return err;
+}
+
 #define	OVL_IOC_GETLWRFHNDLSNUM			_IO('o', 1)
 // DISCUSS: what if MAX_HANDLE_SZ will change?
 #define	OVL_IOC_GETLWRFHNDL			_IOR('o', 2, struct ovl_mnt_opt_fh)
 #define	OVL_IOC_GETUPPRFHNDL			_IOR('o', 3, struct ovl_mnt_opt_fh)
 #define	OVL_IOC_GETWRKFHNDL			_IOR('o', 4, struct ovl_mnt_opt_fh)
+#define	OVL_IOC_GETINFOFD			_IO('o', 5)
 
 static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
@@ -1094,6 +1261,10 @@  static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		ret = ovl_ioctl_get_work_fhandle(file_inode(file)->i_sb, arg);
 		break;
 
+	case OVL_IOC_GETINFOFD:
+		ret = ovl_ioctl_get_info_fd(file_inode(file)->i_sb, arg);
+		break;
+
 	default:
 		ret = -ENOTTY;
 	}