[RFC PATCH] overlayfs: add OVL_IOC_GETINFOFD ioctl that opens ovlinfofd

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxx>
Cc: Andrei Vagin <avagin@xxxxxxxxx>
Cc: Pavel Tikhomirov <ptikhomirov@xxxxxxxxxxxxx>
Cc: Miklos Szeredi <miklos@xxxxxxxxxx>
Cc: David Howells <dhowells@xxxxxxxxxx>
Cc: linux-unionfs@xxxxxxxxxxxxxxx
Cc: linux-fsdevel@xxxxxxxxxxxxxxx
Cc: linux-kernel@xxxxxxxxxxxxxxx
Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@xxxxxxxxxxxxx>
---
 fs/overlayfs/readdir.c | 171 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 171 insertions(+)

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;
 	}
-- 
2.25.1




[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux