@@ -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();
@@ -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;
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@gmail.com> --- drivers/gpu/drm/drm_drv.c | 37 +++++++++++++++++++++++++++++++++++++ include/drm/drmP.h | 1 + 2 files changed, 38 insertions(+)