[RFC v2 1/3] drm: add pseudo filesystem for shared inodes

David Herrmann dh.herrmann at gmail.com
Fri Jan 3 06:41:25 PST 2014


Our current DRM design uses a single address_space for all users of the
same DRM device. However, there is no way to create an anonymous
address_space without an underlying inode. Therefore, we wait for the
first ->open() callback on a registered char-dev and take-over the inode
of the char-dev. This worked well so far, but has several drawbacks:
 - We screw with FS internals and rely on some non-obvious invariants like
   inode->i_mapping being the same as inode->i_data for char-devs.
 - We don't have any address_space prior to the first ->open() from
   user-space. This leads to ugly fallback code and we cannot allocate
   global objects early.

As pointed out by Al-Viro, fs/anon_inode.c is *not* supposed to be used by
drivers for anonymous inode-allocation. Therefore, this patch follows the
proposed alternative solution and adds a pseudo filesystem mount-point to
DRM. We can then allocate private inodes including a private address_space
for each DRM device at initialization time.

Note that we could use:
  sysfs_get_inode(sysfs_mnt->mnt_sb, drm_device->dev->kobj.sd);
to get access to the underlying sysfs-inode of a "struct device" object.
However, most of this information is currently hidden and it's not clear
whether this address_space is suitable for driver access. Thus, unless
linux allows anonymous address_space objects or driver-core provides a
public inode per device, we're left with our own private internal mount
point.

Signed-off-by: David Herrmann <dh.herrmann at gmail.com>
---
 drivers/gpu/drm/drm_drv.c | 37 +++++++++++++++++++++++++++++++++++++
 include/drm/drmP.h        |  1 +
 2 files changed, 38 insertions(+)

diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 345be03..48ee03f 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -49,6 +49,8 @@
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
 #include <drm/drmP.h>
 #include <drm/drm_core.h>
 
@@ -171,6 +173,30 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
 
 #define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
 
+static struct vfsmount *drm_mnt;
+
+struct inode *drm_alloc_inode(void)
+{
+	return alloc_anon_inode(drm_mnt->mnt_sb);
+}
+
+static const struct dentry_operations drm_dops = {
+	.d_dname	= simple_dname,
+};
+
+static struct dentry *drm_mount(struct file_system_type *fs_type, int flags,
+				const char *dev_name, void *data)
+{
+	return mount_pseudo(fs_type, "drm:", NULL, &drm_dops, 0x010203ff);
+}
+
+static struct file_system_type drm_fs = {
+	.name		= "drm",
+	.owner		= THIS_MODULE,
+	.mount		= drm_mount,
+	.kill_sb	= kill_anon_super,
+};
+
 /** File operations structure */
 static const struct file_operations drm_stub_fops = {
 	.owner = THIS_MODULE,
@@ -203,9 +229,19 @@ static int __init drm_core_init(void)
 		goto err_p3;
 	}
 
+	drm_mnt = kern_mount(&drm_fs);
+	if (IS_ERR(drm_mnt)) {
+		ret = PTR_ERR(drm_mnt);
+		DRM_ERROR("Cannot mount pseudo fs: %d\n", ret);
+		goto err_p4;
+	}
+
 	DRM_INFO("Initialized %s %d.%d.%d %s\n",
 		 CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
 	return 0;
+
+err_p4:
+	debugfs_remove(drm_debugfs_root);
 err_p3:
 	drm_sysfs_destroy();
 err_p2:
@@ -218,6 +254,7 @@ err_p1:
 
 static void __exit drm_core_exit(void)
 {
+	kern_unmount(drm_mnt);
 	debugfs_remove(drm_debugfs_root);
 	drm_sysfs_destroy();
 
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 2fe9b5d..02637a5 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1258,6 +1258,7 @@ extern long drm_ioctl(struct file *filp,
 extern long drm_compat_ioctl(struct file *filp,
 			     unsigned int cmd, unsigned long arg);
 extern int drm_lastclose(struct drm_device *dev);
+extern struct inode *drm_alloc_inode(void);
 
 				/* Device support (drm_fops.h) */
 extern struct mutex drm_global_mutex;
-- 
1.8.5.2



More information about the dri-devel mailing list