diff mbox

[RFC,1/3] fs: Introduce drmfs pseudo filesystem interfaces

Message ID 1480575753-5837-2-git-send-email-swati.dhingra@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

swati.dhingra@intel.com Dec. 1, 2016, 7:02 a.m. UTC
From: Swati Dhingra <swati.dhingra@intel.com>

The patch introduces a new pseudo filesystem type, named 'drmfs' which is
intended to house the files for the data generated by drm subsystem that
cannot be accommodated by any of the existing filesystems.
The filesystem is modelled on the lines of existing pseudo-filesystems such
as debugfs/tracefs, and borrows ideas from their implementation.
This filesystem will be appearing at sys/kernel/drm.

A new config 'CONFIG_DRMFS' is introduced to enable/disable the filesystem,
which is dependent on CONFIG_DRM.
The filesystem will not be registered standalone during kernel init time,
instead it is intended to be initialized/registered during drm initialization.

The intent for introduction of the filesystem is to act as a location to hold
various kinds of data output from Linux DRM subsystems, which can't really fit
anywhere else into the existing filesystems such as debugfs/sysfs etc. All these
filesystems have their own constraints and are intended to output a particular
type of data such as attributes and small debug parameter data. Due to these
constraints, there is a need for a new pseudo filesytem, customizable to DRM
specific requirements and catering to the needs to DRM subsystem components

Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
Signed-off-by: Swati Dhingra <swati.dhingra@intel.com>
---
 drivers/gpu/drm/drm_drv.c  |   1 +
 fs/Kconfig                 |   9 +
 fs/Makefile                |   1 +
 fs/drmfs/Makefile          |   4 +
 fs/drmfs/inode.c           | 561 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/drmfs.h      |  56 +++++
 include/uapi/linux/magic.h |   3 +
 7 files changed, 635 insertions(+)
 create mode 100644 fs/drmfs/Makefile
 create mode 100644 fs/drmfs/inode.c
 create mode 100644 include/linux/drmfs.h

Comments

Chris Wilson Dec. 1, 2016, 8:07 a.m. UTC | #1
On Thu, Dec 01, 2016 at 12:32:31PM +0530, swati.dhingra@intel.com wrote:
> +int drmfs_init(void)
> +{
> +	int retval;
> +
> +	retval = sysfs_create_mount_point(kernel_kobj, "drm");
> +	if (retval)
> +		return -EINVAL;
> +
> +	retval = register_filesystem(&drm_fs_type);
> +	if (!retval)
> +		drmfs_registered = true;
> +
> +	return retval;
> +}
> +EXPORT_SYMBOL(drmfs_init);
> +
> +int drmfs_fini(void)
> +{
> +	int retval;
> +
> +	retval = unregister_filesystem(&drm_fs_type);
> +	if (retval)
> +		return retval;
> +
> +	drmfs_registered = false;
> +
> +	sysfs_remove_mount_point(kernel_kobj, "drm");
> +}
> +EXPORT_SYMBOL(drmfs_fini);

This needs to act like a singleton for multiple DRM drivers, i.e.
add a mutex and use drmfs_registered as a reference count (also then
don't call the entrypoint init/fini). Or alternatively (and probably
better?), simply do init/fini from the DRM module init.
-Chris
Chris Wilson Dec. 1, 2016, 8:11 a.m. UTC | #2
On Thu, Dec 01, 2016 at 12:32:31PM +0530, swati.dhingra@intel.com wrote:
> diff --git a/fs/Kconfig b/fs/Kconfig
> index 4bd03a2..7d0ac20 100644
> --- a/fs/Kconfig
> +++ b/fs/Kconfig
> @@ -200,6 +200,15 @@ config HUGETLBFS
>  config HUGETLB_PAGE
>  	def_bool HUGETLBFS
>  
> +config DRMFS
> +	bool "Drmfs file system support"
> +	depends on DRM
> +	help
> +	  Drmfs is a pseudo file system for drm subsystem output data.
> +
> +	  drmfs is a filesystem to hold miscellaneous output data from drm
> +	  subsystems.
> +
>  config ARCH_HAS_GIGANTIC_PAGE
>  	bool
>  
> diff --git a/fs/Makefile b/fs/Makefile
> index ed2b632..b34a96e 100644
> --- a/fs/Makefile
> +++ b/fs/Makefile
> @@ -120,6 +120,7 @@ obj-$(CONFIG_BEFS_FS)		+= befs/
>  obj-$(CONFIG_HOSTFS)		+= hostfs/
>  obj-$(CONFIG_CACHEFILES)	+= cachefiles/
>  obj-$(CONFIG_DEBUG_FS)		+= debugfs/
> +obj-$(CONFIG_DRMFS)		+= drmfs/

A filesystem does not have to live under fs/. Since this is dedicated
and tied to the lifetime of drivers/gpu/drm/drm.ko, we will be happier
with not adding a new MAINTAINERS entry.
-Chris
sourab.gupta@intel.com Dec. 1, 2016, 8:31 a.m. UTC | #3
On Thu, 2016-12-01 at 00:07 -0800, Chris Wilson wrote:
> On Thu, Dec 01, 2016 at 12:32:31PM +0530, swati.dhingra@intel.com wrote:
> > +int drmfs_init(void)
> > +{
> > +	int retval;
> > +
> > +	retval = sysfs_create_mount_point(kernel_kobj, "drm");
> > +	if (retval)
> > +		return -EINVAL;
> > +
> > +	retval = register_filesystem(&drm_fs_type);
> > +	if (!retval)
> > +		drmfs_registered = true;
> > +
> > +	return retval;
> > +}
> > +EXPORT_SYMBOL(drmfs_init);
> > +
> > +int drmfs_fini(void)
> > +{
> > +	int retval;
> > +
> > +	retval = unregister_filesystem(&drm_fs_type);
> > +	if (retval)
> > +		return retval;
> > +
> > +	drmfs_registered = false;
> > +
> > +	sysfs_remove_mount_point(kernel_kobj, "drm");
> > +}
> > +EXPORT_SYMBOL(drmfs_fini);
> 
> This needs to act like a singleton for multiple DRM drivers, i.e.
> add a mutex and use drmfs_registered as a reference count (also then
> don't call the entrypoint init/fini). Or alternatively (and probably
> better?), simply do init/fini from the DRM module init.
> -Chris
> 
Hi Chris,

In the second patch, drmfs_init is called by drm_core_init, which should
thus be called only once (i.e. during drm module init), and likewise for
drmfs_fini which is called during drm_core_exit.
Am I missing something here?
sourab.gupta@intel.com Dec. 1, 2016, 8:37 a.m. UTC | #4
On Thu, 2016-12-01 at 00:11 -0800, Chris Wilson wrote:
> On Thu, Dec 01, 2016 at 12:32:31PM +0530, swati.dhingra@intel.com wrote:
> > diff --git a/fs/Kconfig b/fs/Kconfig
> > index 4bd03a2..7d0ac20 100644
> > --- a/fs/Kconfig
> > +++ b/fs/Kconfig
> > @@ -200,6 +200,15 @@ config HUGETLBFS
> >  config HUGETLB_PAGE
> >  	def_bool HUGETLBFS
> >  
> > +config DRMFS
> > +	bool "Drmfs file system support"
> > +	depends on DRM
> > +	help
> > +	  Drmfs is a pseudo file system for drm subsystem output data.
> > +
> > +	  drmfs is a filesystem to hold miscellaneous output data from drm
> > +	  subsystems.
> > +
> >  config ARCH_HAS_GIGANTIC_PAGE
> >  	bool
> >  
> > diff --git a/fs/Makefile b/fs/Makefile
> > index ed2b632..b34a96e 100644
> > --- a/fs/Makefile
> > +++ b/fs/Makefile
> > @@ -120,6 +120,7 @@ obj-$(CONFIG_BEFS_FS)		+= befs/
> >  obj-$(CONFIG_HOSTFS)		+= hostfs/
> >  obj-$(CONFIG_CACHEFILES)	+= cachefiles/
> >  obj-$(CONFIG_DEBUG_FS)		+= debugfs/
> > +obj-$(CONFIG_DRMFS)		+= drmfs/
> 
> A filesystem does not have to live under fs/. Since this is dedicated
> and tied to the lifetime of drivers/gpu/drm/drm.ko, we will be happier
> with not adding a new MAINTAINERS entry.
> -Chris
> 
Ok, agreed.
So, should we have the drmfs/ source directory (with its associated
files) under drivers/gpu/drm/?
Can you please suggest where should the associated 'DRMFS' config be
defined? Should drm/Kconfig be a good place?
Chris Wilson Dec. 1, 2016, 8:48 a.m. UTC | #5
On Thu, Dec 01, 2016 at 02:01:59PM +0530, sourab gupta wrote:
> On Thu, 2016-12-01 at 00:07 -0800, Chris Wilson wrote:
> > On Thu, Dec 01, 2016 at 12:32:31PM +0530, swati.dhingra@intel.com wrote:
> > > +int drmfs_init(void)
> > > +{
> > > +	int retval;
> > > +
> > > +	retval = sysfs_create_mount_point(kernel_kobj, "drm");
> > > +	if (retval)
> > > +		return -EINVAL;
> > > +
> > > +	retval = register_filesystem(&drm_fs_type);
> > > +	if (!retval)
> > > +		drmfs_registered = true;
> > > +
> > > +	return retval;
> > > +}
> > > +EXPORT_SYMBOL(drmfs_init);
> > > +
> > > +int drmfs_fini(void)
> > > +{
> > > +	int retval;
> > > +
> > > +	retval = unregister_filesystem(&drm_fs_type);
> > > +	if (retval)
> > > +		return retval;
> > > +
> > > +	drmfs_registered = false;
> > > +
> > > +	sysfs_remove_mount_point(kernel_kobj, "drm");
> > > +}
> > > +EXPORT_SYMBOL(drmfs_fini);
> > 
> > This needs to act like a singleton for multiple DRM drivers, i.e.
> > add a mutex and use drmfs_registered as a reference count (also then
> > don't call the entrypoint init/fini). Or alternatively (and probably
> > better?), simply do init/fini from the DRM module init.
> > -Chris
> > 
> Hi Chris,
> 
> In the second patch, drmfs_init is called by drm_core_init, which should
> thus be called only once (i.e. during drm module init), and likewise for
> drmfs_fini which is called during drm_core_exit.
> Am I missing something here?

Nope, that was me missing the change from driver registration to core
between chunks.  The only thing missing here then are the __init,
__exit markers, and to make it perfectly clear that this is a distinct
phase move the calls to init/exit into their own patch.
-Chris
Chris Wilson Dec. 1, 2016, 8:58 a.m. UTC | #6
On Thu, Dec 01, 2016 at 02:07:19PM +0530, sourab gupta wrote:
> On Thu, 2016-12-01 at 00:11 -0800, Chris Wilson wrote:
> > On Thu, Dec 01, 2016 at 12:32:31PM +0530, swati.dhingra@intel.com wrote:
> > > diff --git a/fs/Kconfig b/fs/Kconfig
> > > index 4bd03a2..7d0ac20 100644
> > > --- a/fs/Kconfig
> > > +++ b/fs/Kconfig
> > > @@ -200,6 +200,15 @@ config HUGETLBFS
> > >  config HUGETLB_PAGE
> > >  	def_bool HUGETLBFS
> > >  
> > > +config DRMFS
> > > +	bool "Drmfs file system support"
> > > +	depends on DRM
> > > +	help
> > > +	  Drmfs is a pseudo file system for drm subsystem output data.
> > > +
> > > +	  drmfs is a filesystem to hold miscellaneous output data from drm
> > > +	  subsystems.
> > > +
> > >  config ARCH_HAS_GIGANTIC_PAGE
> > >  	bool
> > >  
> > > diff --git a/fs/Makefile b/fs/Makefile
> > > index ed2b632..b34a96e 100644
> > > --- a/fs/Makefile
> > > +++ b/fs/Makefile
> > > @@ -120,6 +120,7 @@ obj-$(CONFIG_BEFS_FS)		+= befs/
> > >  obj-$(CONFIG_HOSTFS)		+= hostfs/
> > >  obj-$(CONFIG_CACHEFILES)	+= cachefiles/
> > >  obj-$(CONFIG_DEBUG_FS)		+= debugfs/
> > > +obj-$(CONFIG_DRMFS)		+= drmfs/
> > 
> > A filesystem does not have to live under fs/. Since this is dedicated
> > and tied to the lifetime of drivers/gpu/drm/drm.ko, we will be happier
> > with not adding a new MAINTAINERS entry.
> > -Chris
> > 
> Ok, agreed.
> So, should we have the drmfs/ source directory (with its associated
> files) under drivers/gpu/drm/?

If it sticks to one file, drmfs.c. (Slightly breaks the trend, but still
consistent as we are using the drmfs_ prefix.) If we follow the pattern
of having mount.c, file.c, dir.c etc, then drivers/gpu/drm/drmfs/

> Can you please suggest where should the associated 'DRMFS' config be
> defined? Should drm/Kconfig be a good place?

Yes, drivers/gpu/drm/Kconfig.
-Chris
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 6dbb986..84fcfcb 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -27,6 +27,7 @@ 
  */
 
 #include <linux/debugfs.h>
+#include <linux/drmfs.h>
 #include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
diff --git a/fs/Kconfig b/fs/Kconfig
index 4bd03a2..7d0ac20 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -200,6 +200,15 @@  config HUGETLBFS
 config HUGETLB_PAGE
 	def_bool HUGETLBFS
 
+config DRMFS
+	bool "Drmfs file system support"
+	depends on DRM
+	help
+	  Drmfs is a pseudo file system for drm subsystem output data.
+
+	  drmfs is a filesystem to hold miscellaneous output data from drm
+	  subsystems.
+
 config ARCH_HAS_GIGANTIC_PAGE
 	bool
 
diff --git a/fs/Makefile b/fs/Makefile
index ed2b632..b34a96e 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -120,6 +120,7 @@  obj-$(CONFIG_BEFS_FS)		+= befs/
 obj-$(CONFIG_HOSTFS)		+= hostfs/
 obj-$(CONFIG_CACHEFILES)	+= cachefiles/
 obj-$(CONFIG_DEBUG_FS)		+= debugfs/
+obj-$(CONFIG_DRMFS)		+= drmfs/
 obj-$(CONFIG_TRACING)		+= tracefs/
 obj-$(CONFIG_OCFS2_FS)		+= ocfs2/
 obj-$(CONFIG_BTRFS_FS)		+= btrfs/
diff --git a/fs/drmfs/Makefile b/fs/drmfs/Makefile
new file mode 100644
index 0000000..708be0d
--- /dev/null
+++ b/fs/drmfs/Makefile
@@ -0,0 +1,3 @@ 
+drmfs-objs	:= inode.o
+
+obj-$(CONFIG_DRMFS)	+= drmfs.o
diff --git a/fs/drmfs/inode.c b/fs/drmfs/inode.c
new file mode 100644
index 0000000..ada3e18
--- /dev/null
+++ b/fs/drmfs/inode.c
@@ -0,0 +1,561 @@ 
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *	Swati Dhingra <swati.dhingra@intel.com>
+ *	Sourab Gupta <sourab.gupta@intel.com>
+ *	Akash Goel <akash.goel@intel.com>
+ */
+
+/*
+ * drmfs is the filesystem used for output of drm subsystem data
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/kobject.h>
+#include <linux/namei.h>
+#include <linux/drmfs.h>
+#include <linux/fsnotify.h>
+#include <linux/seq_file.h>
+#include <linux/parser.h>
+#include <linux/magic.h>
+#include <linux/slab.h>
+
+#define DRMFS_DEFAULT_MODE	0700
+
+static struct vfsmount *drmfs_mount;
+static int drmfs_mount_count;
+static bool drmfs_registered;
+
+static ssize_t default_read_file(struct file *file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	return 0;
+}
+
+static ssize_t default_write_file(struct file *file, const char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	return count;
+}
+
+static const struct file_operations drmfs_default_file_operations = {
+	.read =		default_read_file,
+	.write =	default_write_file,
+	.open =		simple_open,
+	.llseek =	noop_llseek,
+};
+
+static struct inode *drmfs_get_inode(struct super_block *sb)
+{
+	struct inode *inode = new_inode(sb);
+
+	if (inode) {
+		inode->i_ino = get_next_ino();
+		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	}
+	return inode;
+}
+
+struct drmfs_mount_opts {
+	kuid_t uid;
+	kgid_t gid;
+	umode_t mode;
+};
+
+enum {
+	Opt_uid,
+	Opt_gid,
+	Opt_mode,
+	Opt_err
+};
+
+static const match_table_t tokens = {
+	{Opt_uid, "uid=%u"},
+	{Opt_gid, "gid=%u"},
+	{Opt_mode, "mode=%o"},
+	{Opt_err, NULL}
+};
+
+struct drmfs_fs_info {
+	struct drmfs_mount_opts mount_opts;
+};
+
+static int drmfs_parse_options(char *data, struct drmfs_mount_opts *opts)
+{
+	substring_t args[MAX_OPT_ARGS];
+	int option;
+	int token;
+	kuid_t uid;
+	kgid_t gid;
+	char *p;
+
+	opts->mode = DRMFS_DEFAULT_MODE;
+
+	while ((p = strsep(&data, ",")) != NULL) {
+		if (!*p)
+			continue;
+
+		token = match_token(p, tokens, args);
+		switch (token) {
+		case Opt_uid:
+			if (match_int(&args[0], &option))
+				return -EINVAL;
+			uid = make_kuid(current_user_ns(), option);
+			if (!uid_valid(uid))
+				return -EINVAL;
+			opts->uid = uid;
+			break;
+		case Opt_gid:
+			if (match_int(&args[0], &option))
+				return -EINVAL;
+			gid = make_kgid(current_user_ns(), option);
+			if (!gid_valid(gid))
+				return -EINVAL;
+			opts->gid = gid;
+			break;
+		case Opt_mode:
+			if (match_octal(&args[0], &option))
+				return -EINVAL;
+			opts->mode = option & S_IALLUGO;
+			break;
+		/*
+		 * We might like to report bad mount options here
+		 */
+		}
+	}
+
+	return 0;
+}
+
+static int drmfs_apply_options(struct super_block *sb)
+{
+	struct drmfs_fs_info *fsi = sb->s_fs_info;
+	struct inode *inode = sb->s_root->d_inode;
+	struct drmfs_mount_opts *opts = &fsi->mount_opts;
+
+	inode->i_mode &= ~S_IALLUGO;
+	inode->i_mode |= opts->mode;
+
+	inode->i_uid = opts->uid;
+	inode->i_gid = opts->gid;
+
+	return 0;
+}
+
+static int drmfs_remount(struct super_block *sb, int *flags, char *data)
+{
+	int err;
+	struct drmfs_fs_info *fsi = sb->s_fs_info;
+
+	sync_filesystem(sb);
+	err = drmfs_parse_options(data, &fsi->mount_opts);
+	if (err)
+		goto fail;
+
+	drmfs_apply_options(sb);
+
+fail:
+	return err;
+}
+
+static int drmfs_show_options(struct seq_file *m, struct dentry *root)
+{
+	struct drmfs_fs_info *fsi = root->d_sb->s_fs_info;
+	struct drmfs_mount_opts *opts = &fsi->mount_opts;
+
+	if (!uid_eq(opts->uid, GLOBAL_ROOT_UID))
+		seq_printf(m, ",uid=%u",
+			   from_kuid_munged(&init_user_ns, opts->uid));
+	if (!gid_eq(opts->gid, GLOBAL_ROOT_GID))
+		seq_printf(m, ",gid=%u",
+			   from_kgid_munged(&init_user_ns, opts->gid));
+	if (opts->mode != DRMFS_DEFAULT_MODE)
+		seq_printf(m, ",mode=%o", opts->mode);
+
+	return 0;
+}
+
+static const struct super_operations drmfs_super_operations = {
+	.statfs		= simple_statfs,
+	.remount_fs	= drmfs_remount,
+	.show_options	= drmfs_show_options,
+};
+
+static int drm_fill_super(struct super_block *sb, void *data, int silent)
+{
+	static struct tree_descr drm_files[] = { {""} };
+	struct drmfs_fs_info *fsi;
+	int err;
+
+	save_mount_options(sb, data);
+
+	fsi = kzalloc(sizeof(struct drmfs_fs_info), GFP_KERNEL);
+	sb->s_fs_info = fsi;
+	if (!fsi) {
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	err = drmfs_parse_options(data, &fsi->mount_opts);
+	if (err)
+		goto fail;
+
+	err  =  simple_fill_super(sb, DRMFS_MAGIC, drm_files);
+	if (err)
+		goto fail;
+
+	sb->s_op = &drmfs_super_operations;
+
+	drmfs_apply_options(sb);
+
+	return 0;
+
+fail:
+	kfree(fsi);
+	sb->s_fs_info = NULL;
+	return err;
+}
+
+static struct dentry *drm_mount(struct file_system_type *fs_type,
+			int flags, const char *dev_name,
+			void *data)
+{
+	return mount_single(fs_type, flags, data, drm_fill_super);
+}
+
+static struct file_system_type drm_fs_type = {
+	.owner =	THIS_MODULE,
+	.name =		"drmfs",
+	.mount =	drm_mount,
+	.kill_sb =	kill_litter_super,
+};
+MODULE_ALIAS_FS("drmfs");
+
+static struct dentry *start_creating(const char *name, struct dentry *parent)
+{
+	struct dentry *dentry;
+	int error;
+
+	pr_debug("drmfs: creating file '%s'\n", name);
+
+	error = simple_pin_fs(&drm_fs_type, &drmfs_mount,
+			      &drmfs_mount_count);
+	if (error)
+		return ERR_PTR(error);
+
+	/* If the parent is not specified, we create it in the root.
+	 * We need the root dentry to do this, which is in the super
+	 * block. A pointer to that is in the struct vfsmount that we
+	 * have around.
+	 */
+	if (!parent)
+		parent = drmfs_mount->mnt_root;
+
+	inode_lock(parent->d_inode);
+	dentry = lookup_one_len(name, parent, strlen(name));
+	if (!IS_ERR(dentry) && dentry->d_inode) {
+		dput(dentry);
+		dentry = ERR_PTR(-EEXIST);
+	}
+
+	if (IS_ERR(dentry)) {
+		inode_unlock(parent->d_inode);
+		simple_release_fs(&drmfs_mount, &drmfs_mount_count);
+	}
+
+	return dentry;
+}
+
+static struct dentry *failed_creating(struct dentry *dentry)
+{
+	inode_unlock(dentry->d_parent->d_inode);
+	dput(dentry);
+	simple_release_fs(&drmfs_mount, &drmfs_mount_count);
+	return NULL;
+}
+
+static struct dentry *end_creating(struct dentry *dentry)
+{
+	inode_unlock(dentry->d_parent->d_inode);
+	return dentry;
+}
+
+/**
+ * drmfs_create_file - create a file in the drmfs filesystem
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have.
+ * @parent: a pointer to the parent dentry for this file.  This should be a
+ *          directory dentry if set.  If this parameter is NULL, then the
+ *          file will be created in the root of the drmfs filesystem.
+ * @data: a pointer to something that the caller will want to get to later
+ *        on.  The inode.i_private pointer will point to this value on
+ *        the open() call.
+ * @fops: a pointer to a struct file_operations that should be used for
+ *        this file.
+ *
+ * This is the basic "create a file" function for drmfs.  It allows for a
+ * wide range of flexibility in creating a file, or a directory (if you want
+ * to create a directory, the drmfs_create_dir() function is
+ * recommended to be used instead.)
+ *
+ * This function will return a pointer to a dentry if it succeeds.  This
+ * pointer must be passed to the drmfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+ * you are responsible here.)  If an error occurs, %NULL will be returned.
+ *
+ */
+struct dentry *drmfs_create_file(const char *name, umode_t mode,
+				   struct dentry *parent, void *data,
+				   const struct file_operations *fops)
+{
+	struct dentry *dentry;
+	struct inode *inode;
+
+	if (!(mode & S_IFMT))
+		mode |= S_IFREG;
+
+	if (WARN_ON(!S_ISREG(mode)))
+		return NULL;
+
+	dentry = start_creating(name, parent);
+
+	if (IS_ERR(dentry))
+		return NULL;
+
+	inode = drmfs_get_inode(dentry->d_sb);
+	if (unlikely(!inode))
+		return failed_creating(dentry);
+
+	inode->i_mode = mode;
+	inode->i_fop = fops ? fops : &drmfs_default_file_operations;
+	inode->i_private = data;
+	d_instantiate(dentry, inode);
+	fsnotify_create(dentry->d_parent->d_inode, dentry);
+	return end_creating(dentry);
+}
+EXPORT_SYMBOL(drmfs_create_file);
+
+static struct dentry *__create_dir(const char *name, struct dentry *parent,
+				   const struct inode_operations *ops)
+{
+	struct dentry *dentry = start_creating(name, parent);
+	struct inode *inode;
+
+	if (IS_ERR(dentry))
+		return NULL;
+
+	inode = drmfs_get_inode(dentry->d_sb);
+	if (unlikely(!inode))
+		return failed_creating(dentry);
+
+	inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
+	inode->i_op = ops;
+	inode->i_fop = &simple_dir_operations;
+
+	/* directory inodes start off with i_nlink == 2 (for "." entry) */
+	inc_nlink(inode);
+	d_instantiate(dentry, inode);
+	inc_nlink(dentry->d_parent->d_inode);
+	fsnotify_mkdir(dentry->d_parent->d_inode, dentry);
+	return end_creating(dentry);
+}
+
+/**
+ * drmfs_create_dir - create a directory in the drmfs filesystem
+ * @name: a pointer to a string containing the name of the directory to
+ *        create.
+ * @parent: a pointer to the parent dentry for this file.  This should be a
+ *          directory dentry if set.  If this parameter is NULL, then the
+ *          directory will be created in the root of the drmfs filesystem.
+ *
+ * This function creates a directory in drmfs with the given name.
+ *
+ * This function will return a pointer to a dentry if it succeeds.  This
+ * pointer must be passed to the drmfs_remove() function when the file is
+ * to be removed. If an error occurs, %NULL will be returned.
+ *
+ */
+struct dentry *drmfs_create_dir(const char *name, struct dentry *parent)
+{
+	return __create_dir(name, parent, &simple_dir_inode_operations);
+}
+EXPORT_SYMBOL(drmfs_create_dir);
+
+static int __drmfs_remove(struct dentry *dentry, struct dentry *parent)
+{
+	int ret = 0;
+
+	if (simple_positive(dentry)) {
+		if (dentry->d_inode) {
+			dget(dentry);
+			switch (dentry->d_inode->i_mode & S_IFMT) {
+			case S_IFDIR:
+				ret = simple_rmdir(parent->d_inode, dentry);
+				break;
+			default:
+				simple_unlink(parent->d_inode, dentry);
+				break;
+			}
+			if (!ret)
+				d_delete(dentry);
+			dput(dentry);
+		}
+	}
+	return ret;
+}
+
+
+/**
+ * drmfs_remove - removes a file or directory from the drmfs filesystem
+ * @dentry: a pointer to a the dentry of the file or directory to be
+ *          removed.
+ *
+ * This function removes a file or directory in drmfs that was previously
+ * created with a call to another drmfs function (like
+ * drmfs_create_file() or variants thereof.)
+ */
+void drmfs_remove(struct dentry *dentry)
+{
+	struct dentry *parent;
+	int ret;
+
+	if (IS_ERR_OR_NULL(dentry))
+		return;
+
+	parent = dentry->d_parent;
+	inode_lock(parent->d_inode);
+	ret = __drmfs_remove(dentry, parent);
+	inode_unlock(parent->d_inode);
+	if (!ret)
+		simple_release_fs(&drmfs_mount, &drmfs_mount_count);
+}
+EXPORT_SYMBOL(drmfs_remove);
+
+/**
+ * drmfs_remove_recursive - recursively removes a directory
+ * @dentry: a pointer to a the dentry of the directory to be removed.
+ *
+ * This function recursively removes a directory tree in drmfs that
+ * was previously created with a call to another drmfs function
+ * (like drmfs_create_file() or variants thereof.)
+ */
+void drmfs_remove_recursive(struct dentry *dentry)
+{
+	struct dentry *child, *parent;
+
+	if (IS_ERR_OR_NULL(dentry))
+		return;
+
+	parent = dentry;
+ down:
+	inode_lock(parent->d_inode);
+ loop:
+	/*
+	 * The parent->d_subdirs is protected by the d_lock. Outside that
+	 * lock, the child can be unlinked and set to be freed which can
+	 * use the d_u.d_child as the rcu head and corrupt this list.
+	 */
+	spin_lock(&parent->d_lock);
+	list_for_each_entry(child, &parent->d_subdirs, d_child) {
+		if (!simple_positive(child))
+			continue;
+
+		/* perhaps simple_empty(child) makes more sense */
+		if (!list_empty(&child->d_subdirs)) {
+			spin_unlock(&parent->d_lock);
+			inode_unlock(parent->d_inode);
+			parent = child;
+			goto down;
+		}
+
+		spin_unlock(&parent->d_lock);
+
+		if (!__drmfs_remove(child, parent))
+			simple_release_fs(&drmfs_mount, &drmfs_mount_count);
+
+		/*
+		 * The parent->d_lock protects against child from unlinking
+		 * from d_subdirs. When releasing the parent->d_lock we can
+		 * no longer trust that the next pointer is valid.
+		 * Restart the loop. We'll skip this one with the
+		 * simple_positive() check.
+		 */
+		goto loop;
+	}
+	spin_unlock(&parent->d_lock);
+
+	inode_unlock(parent->d_inode);
+	child = parent;
+	parent = parent->d_parent;
+	inode_lock(parent->d_inode);
+
+	if (child != dentry)
+		/* go up */
+		goto loop;
+
+	if (!__drmfs_remove(child, parent))
+		simple_release_fs(&drmfs_mount, &drmfs_mount_count);
+	inode_unlock(parent->d_inode);
+}
+EXPORT_SYMBOL(drmfs_remove_recursive);
+
+/**
+ * drmfs_initialized - Tells whether drmfs has been registered
+ */
+bool drmfs_initialized(void)
+{
+	return drmfs_registered;
+}
+EXPORT_SYMBOL(drmfs_initialized);
+
+int drmfs_init(void)
+{
+	int retval;
+
+	retval = sysfs_create_mount_point(kernel_kobj, "drm");
+	if (retval)
+		return -EINVAL;
+
+	retval = register_filesystem(&drm_fs_type);
+	if (!retval)
+		drmfs_registered = true;
+
+	return retval;
+}
+EXPORT_SYMBOL(drmfs_init);
+
+int drmfs_fini(void)
+{
+	int retval;
+
+	retval = unregister_filesystem(&drm_fs_type);
+	if (retval)
+		return retval;
+
+	drmfs_registered = false;
+
+	sysfs_remove_mount_point(kernel_kobj, "drm");
+}
+EXPORT_SYMBOL(drmfs_fini);
diff --git a/include/linux/drmfs.h b/include/linux/drmfs.h
new file mode 100644
index 0000000..3091480
--- /dev/null
+++ b/include/linux/drmfs.h
@@ -0,0 +1,56 @@ 
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *	Swati Dhingra <swati.dhingra@intel.com>
+ *	Sourab Gupta <sourab.gupta@intel.com>
+ *	Akash Goel <akash.goel@intel.com>
+ */
+
+#ifndef _DRMFS_H_
+#define _DRMFS_H_
+
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+
+#include <linux/types.h>
+
+struct file_operations;
+
+#ifdef CONFIG_DRMFS
+
+struct dentry *drmfs_create_file(const char *name, umode_t mode,
+				   struct dentry *parent, void *data,
+				   const struct file_operations *fops);
+
+struct dentry *drmfs_create_dir(const char *name, struct dentry *parent);
+
+void drmfs_remove(struct dentry *dentry);
+void drmfs_remove_recursive(struct dentry *dentry);
+
+bool drmfs_initialized(void);
+int drmfs_init(void);
+int drmfs_fini(void);
+
+#endif /* CONFIG_DRMFS */
+
+#endif
diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
index 9bd5594..ef01eb7 100644
--- a/include/uapi/linux/magic.h
+++ b/include/uapi/linux/magic.h
@@ -61,6 +61,9 @@ 
 #define STACK_END_MAGIC		0x57AC6E9D
 
 #define TRACEFS_MAGIC          0x74726163
+#define DRMFS_MAGIC	       0x84724143      /* some random number.
+						* Is there a better way?
+						*/
 
 #define V9FS_MAGIC		0x01021997