All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/3] Introduce drmfs pseudo filesystem for drm subsystem
@ 2016-12-01  8:14 swati.dhingra
  2016-12-01  8:14 ` [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces swati.dhingra
                   ` (4 more replies)
  0 siblings, 5 replies; 20+ messages in thread
From: swati.dhingra @ 2016-12-01  8:14 UTC (permalink / raw)
  To: intel-gfx; +Cc: Swati Dhingra

From: Swati Dhingra <swati.dhingra@intel.com>

Currently, for the purpose of providing output debug/loggging/crc and various
other kinds of data from DRM layer to userspace, we don't have a standard
filesystem, which would suffice for all the usecases. The filesystems used
currently such as debugfs/sysfs have their own constraints and are intended
to output a particular type of data. For instance, sysfs is suitable for
exporting only small data in form of attributes, thus not suitable to export
large data such as error states/logs/crc etc. Likewise for debugfs, which is
not available in production kernels, and may not be best place to hold certain
kinds of data. As a result, we currently are creating certain files in these
filesystems, which are not particularly suited there (For, i915, guc_log is a
case in point, which is currently created in debugfs, but not particularly
suited there).

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. This will provide a unified location to hold various
kinds of data from Linux DRM subsystems, for the files which can't really fit
anywhere else into the existing filesystems.

In this patch series, we have introduced a pseudo filesystem named as 'drmfs'
for now. The filesystem is introduced in the first patch, and the subsequent
patches make use of the filesystem interfaces, in drm driver, and making them
available for use by the drm subsystem components, one of which is i915.
We've moved the location of i915 GuC logs from debugfs to drmfs in the third
patch. Subsequently, more such files such as pipe_crc, error states, memory
stats, etc. can be move to this filesystem, if the idea introduced here is
acceptable per se. The filesystem introduced is being used to house the data
generated by i915 driver in this patch series, but will hopefully be generic
enough to provide scope for usage by any other drm subsystem component.

The patch series is being floated as RFC to gather feedback on the idea and
infrastructure proposed here and it's suitability to address the specific
problem statement/use case.

v2: fix the bat failures caused due to missing config check

Swati Dhingra (3):
  fs: Introduce drmfs pseudo filesystem interfaces
  drm: Register drmfs filesystem from drm init
  drm/i915: Creating guc log file in drmfs instead of debugfs

 drivers/gpu/drm/drm_drv.c                  |  23 ++
 drivers/gpu/drm/i915/i915_guc_submission.c |  31 +-
 fs/Kconfig                                 |   9 +
 fs/Makefile                                |   1 +
 fs/drmfs/Makefile                          |   4 +
 fs/drmfs/inode.c                           | 561 +++++++++++++++++++++++++++++
 include/drm/drm_drv.h                      |   3 +
 include/linux/drmfs.h                      |  56 +++
 include/uapi/linux/magic.h                 |   3 +
 9 files changed, 670 insertions(+), 21 deletions(-)
 create mode 100644 fs/drmfs/Makefile
 create mode 100644 fs/drmfs/inode.c
 create mode 100644 include/linux/drmfs.h

-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-01  8:14 [RFC 0/3] Introduce drmfs pseudo filesystem for drm subsystem swati.dhingra
@ 2016-12-01  8:14 ` swati.dhingra
  2016-12-02  7:53   ` Daniel Vetter
  2016-12-02 22:40   ` Matt Roper
  2016-12-01  8:14 ` [RFC 2/3] drm: Register drmfs filesystem from drm init swati.dhingra
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 20+ messages in thread
From: swati.dhingra @ 2016-12-01  8:14 UTC (permalink / raw)
  To: intel-gfx; +Cc: Sourab Gupta, Swati Dhingra

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          |   3 +
 fs/drmfs/inode.c           | 561 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/drmfs.h      |  56 +++++
 include/uapi/linux/magic.h |   3 +
 7 files changed, 634 insertions(+)
 create mode 100644 fs/drmfs/Makefile
 create mode 100644 fs/drmfs/inode.c
 create mode 100644 include/linux/drmfs.h

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..ac87e497
--- /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..9220705
--- /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
 
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC 2/3] drm: Register drmfs filesystem from drm init
  2016-12-01  8:14 [RFC 0/3] Introduce drmfs pseudo filesystem for drm subsystem swati.dhingra
  2016-12-01  8:14 ` [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces swati.dhingra
@ 2016-12-01  8:14 ` swati.dhingra
  2016-12-02  7:57   ` Daniel Vetter
  2016-12-01  8:14 ` [RFC 3/3] drm/i915: Creating guc log file in drmfs instead of debugfs swati.dhingra
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: swati.dhingra @ 2016-12-01  8:14 UTC (permalink / raw)
  To: intel-gfx; +Cc: Sourab Gupta, Swati Dhingra

From: Swati Dhingra <swati.dhingra@intel.com>

During drm module initialization, drm_core_init initializes the drmfs
filesystem and register this with kernel. A driver specific directory is created
inside drmfs root, and dentry of this directory is saved for subsequent use
by the driver (e.g. i915). The driver can then create files/directories inside
this root directory directly.
In case of i915 driver, the top directory is created at '/sys/kernel/drm/i915'.

Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
Signed-off-by: Swati Dhingra <swati.dhingra@intel.com>
---
 drivers/gpu/drm/drm_drv.c | 22 ++++++++++++++++++++++
 include/drm/drm_drv.h     |  3 +++
 2 files changed, 25 insertions(+)

diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 84fcfcb..ead360bd 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -688,6 +688,14 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
 {
 	int ret;
 
+#ifdef CONFIG_DRMFS
+	dev->driver->drmfs_root = drmfs_create_dir(dev->driver->name, NULL);
+	if (IS_ERR(dev->driver->drmfs_root)) {
+		DRM_ERROR("Failed to get drmfs root dentry\n");
+		return PTR_ERR(dev->driver->drmfs_root);
+	}
+#endif
+
 	mutex_lock(&drm_global_mutex);
 
 	ret = drm_minor_register(dev, DRM_MINOR_CONTROL);
@@ -758,6 +766,9 @@ void drm_dev_unregister(struct drm_device *dev)
 	drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
 	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
+#ifdef CONFIG_DRMFS
+	drmfs_remove(dev->driver->drmfs_root);
+#endif
 }
 EXPORT_SYMBOL(drm_dev_unregister);
 
@@ -825,6 +836,9 @@ static void drm_core_exit(void)
 {
 	unregister_chrdev(DRM_MAJOR, "drm");
 	debugfs_remove(drm_debugfs_root);
+#ifdef CONFIG_DRMFS
+	drmfs_fini();
+#endif
 	drm_sysfs_destroy();
 	idr_destroy(&drm_minors_idr);
 	drm_connector_ida_destroy();
@@ -845,6 +859,14 @@ static int __init drm_core_init(void)
 		goto error;
 	}
 
+#ifdef CONFIG_DRMFS
+	ret = drmfs_init();
+	if (ret < 0) {
+		DRM_ERROR("Cannot create DRM FS: %d\n", ret);
+		goto error;
+	}
+#endif
+
 	drm_debugfs_root = debugfs_create_dir("dri", NULL);
 	if (!drm_debugfs_root) {
 		ret = -ENOMEM;
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index aad8bba..34804de 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -403,6 +403,9 @@ struct drm_driver {
 
 	/* List of devices hanging off this driver with stealth attach. */
 	struct list_head legacy_dev_list;
+
+	/* drmfs parent directory dentry for this driver */
+	struct dentry *drmfs_root;
 };
 
 extern __printf(6, 7)
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC 3/3] drm/i915: Creating guc log file in drmfs instead of debugfs
  2016-12-01  8:14 [RFC 0/3] Introduce drmfs pseudo filesystem for drm subsystem swati.dhingra
  2016-12-01  8:14 ` [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces swati.dhingra
  2016-12-01  8:14 ` [RFC 2/3] drm: Register drmfs filesystem from drm init swati.dhingra
@ 2016-12-01  8:14 ` swati.dhingra
  2016-12-01  8:45 ` ✓ Fi.CI.BAT: success for Introduce drmfs pseudo filesystem for drm subsystem (rev2) Patchwork
  2016-12-02  7:52 ` [RFC 0/3] Introduce drmfs pseudo filesystem for drm subsystem Daniel Vetter
  4 siblings, 0 replies; 20+ messages in thread
From: swati.dhingra @ 2016-12-01  8:14 UTC (permalink / raw)
  To: intel-gfx; +Cc: Sourab Gupta, Swati Dhingra

From: Swati Dhingra <swati.dhingra@intel.com>

In the current scenario, the relay API fit well only with debugfs, due to
availability of parent dentry. Any other existing filesystem was not feasible for
holding guc logs, due to incompatibility with relay. But this makes the  guc_log
file unavailable on the production kernels.

GuC log file can therefore be one of candidates for movement to the drmfs
filesystem, which can satisfy all the requirements needed by relay API, and can
house any relayfs based output file.

The patch moves the parent directory of guc 'log_dir' from debugfs_root to
drmfs_root, while using the drmfs api's to create the requisite files.

Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
Signed-off-by: Swati Dhingra <swati.dhingra@intel.com>
---
 drivers/gpu/drm/i915/i915_guc_submission.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 4462112..cd2e8ed 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -24,6 +24,7 @@
 #include <linux/firmware.h>
 #include <linux/circ_buf.h>
 #include <linux/debugfs.h>
+#include <linux/drmfs.h>
 #include <linux/relay.h>
 #include "i915_drv.h"
 #include "intel_guc.h"
@@ -923,7 +924,7 @@ static int subbuf_start_callback(struct rchan_buf *buf,
 }
 
 /*
- * file_create() callback. Creates relay file in debugfs.
+ * file_create() callback. Creates relay file.
  */
 static struct dentry *create_buf_file_callback(const char *filename,
 					       struct dentry *parent,
@@ -949,17 +950,26 @@ static struct dentry *create_buf_file_callback(const char *filename,
 	 * dentry of the file associated with the channel buffer and that file's
 	 * name need not be same as the filename passed as an argument.
 	 */
+#if defined(CONFIG_DRMFS)
+	buf_file = drmfs_create_file("guc_log", mode,
+				       parent, buf, &relay_file_operations);
+#else
 	buf_file = debugfs_create_file("guc_log", mode,
 				       parent, buf, &relay_file_operations);
+#endif
 	return buf_file;
 }
 
 /*
- * file_remove() default callback. Removes relay file in debugfs.
+ * file_remove() default callback. Removes relay file.
  */
 static int remove_buf_file_callback(struct dentry *dentry)
 {
+#if defined(CONFIG_DRMFS)
+	drmfs_remove(dentry);
+#else
 	debugfs_remove(dentry);
+#endif
 	return 0;
 }
 
@@ -1009,6 +1019,10 @@ static int guc_log_create_relay_file(struct intel_guc *guc)
 	struct dentry *log_dir;
 	int ret;
 
+#if defined(CONFIG_DRMFS)
+	/* Create the log file in drmfs dir: /sys/kernel/drm/i915/ */
+	log_dir = dev_priv->drm.driver->drmfs_root;
+#else
 	/* For now create the log file in /sys/kernel/debug/dri/0 dir */
 	log_dir = dev_priv->drm.primary->debugfs_root;
 
@@ -1021,10 +1035,12 @@ static int guc_log_create_relay_file(struct intel_guc *guc)
 	 *      relay channel.
 	 * ii)  Should be able to use 'relay_file_operations' fops for the file.
 	 * iii) Set the 'i_private' field of file's inode to the pointer of
-	 *	relay channel buffer.
+	 *      relay channel buffer.
 	 */
+#endif
+
 	if (!log_dir) {
-		DRM_ERROR("Debugfs dir not available yet for GuC log file\n");
+		DRM_ERROR("Root dir not available yet for GuC log file\n");
 		return -ENODEV;
 	}
 
@@ -1265,7 +1281,7 @@ static int guc_log_create_extras(struct intel_guc *guc)
 	if (!guc->log.relay_chan) {
 		/* Create a relay channel, so that we have buffers for storing
 		 * the GuC firmware logs, the channel will be linked with a file
-		 * later on when debugfs is registered.
+		 * later on when debugfs/drmfs is registered.
 		 */
 		ret = guc_log_create_relay_channel(guc);
 		if (ret)
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* ✓ Fi.CI.BAT: success for Introduce drmfs pseudo filesystem for drm subsystem (rev2)
  2016-12-01  8:14 [RFC 0/3] Introduce drmfs pseudo filesystem for drm subsystem swati.dhingra
                   ` (2 preceding siblings ...)
  2016-12-01  8:14 ` [RFC 3/3] drm/i915: Creating guc log file in drmfs instead of debugfs swati.dhingra
@ 2016-12-01  8:45 ` Patchwork
  2016-12-02  7:52 ` [RFC 0/3] Introduce drmfs pseudo filesystem for drm subsystem Daniel Vetter
  4 siblings, 0 replies; 20+ messages in thread
From: Patchwork @ 2016-12-01  8:45 UTC (permalink / raw)
  To: swati.dhingra; +Cc: intel-gfx

== Series Details ==

Series: Introduce drmfs pseudo filesystem for drm subsystem (rev2)
URL   : https://patchwork.freedesktop.org/series/16203/
State : success

== Summary ==

Series 16203v2 Introduce drmfs pseudo filesystem for drm subsystem
https://patchwork.freedesktop.org/api/1.0/series/16203/revisions/2/mbox/


fi-bdw-5557u     total:245  pass:230  dwarn:0   dfail:0   fail:0   skip:15 
fi-bsw-n3050     total:245  pass:205  dwarn:0   dfail:0   fail:0   skip:40 
fi-byt-j1900     total:245  pass:217  dwarn:0   dfail:0   fail:0   skip:28 
fi-byt-n2820     total:245  pass:213  dwarn:0   dfail:0   fail:0   skip:32 
fi-hsw-4770      total:245  pass:225  dwarn:0   dfail:0   fail:0   skip:20 
fi-hsw-4770r     total:245  pass:225  dwarn:0   dfail:0   fail:0   skip:20 
fi-ilk-650       total:245  pass:192  dwarn:0   dfail:0   fail:0   skip:53 
fi-ivb-3520m     total:245  pass:223  dwarn:0   dfail:0   fail:0   skip:22 
fi-ivb-3770      total:245  pass:223  dwarn:0   dfail:0   fail:0   skip:22 
fi-kbl-7500u     total:245  pass:223  dwarn:0   dfail:0   fail:0   skip:22 
fi-skl-6260u     total:245  pass:231  dwarn:0   dfail:0   fail:0   skip:14 
fi-skl-6700hq    total:245  pass:224  dwarn:0   dfail:0   fail:0   skip:21 
fi-skl-6700k     total:245  pass:223  dwarn:1   dfail:0   fail:0   skip:21 
fi-skl-6770hq    total:245  pass:231  dwarn:0   dfail:0   fail:0   skip:14 
fi-snb-2520m     total:245  pass:213  dwarn:0   dfail:0   fail:0   skip:32 
fi-snb-2600      total:245  pass:212  dwarn:0   dfail:0   fail:0   skip:33 
fi-bxt-t5700 failed to connect after reboot

7fb9612344bbf021a5a3589df82077023dae5e1d drm-tip: 2016y-12m-01d-07h-38m-22s UTC integration manifest
2e85dc9 drm/i915: Creating guc log file in drmfs instead of debugfs
9a06379 drm: Register drmfs filesystem from drm init
69e3465 fs: Introduce drmfs pseudo filesystem interfaces

== Logs ==

For more details see: https://intel-gfx-ci.01.org/CI/Patchwork_3158/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 0/3] Introduce drmfs pseudo filesystem for drm subsystem
  2016-12-01  8:14 [RFC 0/3] Introduce drmfs pseudo filesystem for drm subsystem swati.dhingra
                   ` (3 preceding siblings ...)
  2016-12-01  8:45 ` ✓ Fi.CI.BAT: success for Introduce drmfs pseudo filesystem for drm subsystem (rev2) Patchwork
@ 2016-12-02  7:52 ` Daniel Vetter
  4 siblings, 0 replies; 20+ messages in thread
From: Daniel Vetter @ 2016-12-02  7:52 UTC (permalink / raw)
  To: swati.dhingra; +Cc: intel-gfx

On Thu, Dec 01, 2016 at 01:44:14PM +0530, swati.dhingra@intel.com wrote:
> From: Swati Dhingra <swati.dhingra@intel.com>
> 
> Currently, for the purpose of providing output debug/loggging/crc and various
> other kinds of data from DRM layer to userspace, we don't have a standard
> filesystem, which would suffice for all the usecases. The filesystems used
> currently such as debugfs/sysfs have their own constraints and are intended
> to output a particular type of data. For instance, sysfs is suitable for
> exporting only small data in form of attributes, thus not suitable to export
> large data such as error states/logs/crc etc. Likewise for debugfs, which is
> not available in production kernels, and may not be best place to hold certain
> kinds of data. As a result, we currently are creating certain files in these
> filesystems, which are not particularly suited there (For, i915, guc_log is a
> case in point, which is currently created in debugfs, but not particularly
> suited there).
> 
> 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. This will provide a unified location to hold various
> kinds of data from Linux DRM subsystems, for the files which can't really fit
> anywhere else into the existing filesystems.
> 
> In this patch series, we have introduced a pseudo filesystem named as 'drmfs'
> for now. The filesystem is introduced in the first patch, and the subsequent
> patches make use of the filesystem interfaces, in drm driver, and making them
> available for use by the drm subsystem components, one of which is i915.
> We've moved the location of i915 GuC logs from debugfs to drmfs in the third
> patch. Subsequently, more such files such as pipe_crc, error states, memory
> stats, etc. can be move to this filesystem, if the idea introduced here is
> acceptable per se. The filesystem introduced is being used to house the data
> generated by i915 driver in this patch series, but will hopefully be generic
> enough to provide scope for usage by any other drm subsystem component.
> 
> The patch series is being floated as RFC to gather feedback on the idea and
> infrastructure proposed here and it's suitability to address the specific
> problem statement/use case.
> 
> v2: fix the bat failures caused due to missing config check

This needs to be cc'ed to dri-devel for discussion of the drmfs part.
Please cc the entire patch series so that everyone has the full context.
-Daniel

> 
> Swati Dhingra (3):
>   fs: Introduce drmfs pseudo filesystem interfaces
>   drm: Register drmfs filesystem from drm init
>   drm/i915: Creating guc log file in drmfs instead of debugfs
> 
>  drivers/gpu/drm/drm_drv.c                  |  23 ++
>  drivers/gpu/drm/i915/i915_guc_submission.c |  31 +-
>  fs/Kconfig                                 |   9 +
>  fs/Makefile                                |   1 +
>  fs/drmfs/Makefile                          |   4 +
>  fs/drmfs/inode.c                           | 561 +++++++++++++++++++++++++++++
>  include/drm/drm_drv.h                      |   3 +
>  include/linux/drmfs.h                      |  56 +++
>  include/uapi/linux/magic.h                 |   3 +
>  9 files changed, 670 insertions(+), 21 deletions(-)
>  create mode 100644 fs/drmfs/Makefile
>  create mode 100644 fs/drmfs/inode.c
>  create mode 100644 include/linux/drmfs.h
> 
> -- 
> 2.7.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-01  8:14 ` [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces swati.dhingra
@ 2016-12-02  7:53   ` Daniel Vetter
  2016-12-02  8:27     ` sourab gupta
  2016-12-02 22:40   ` Matt Roper
  1 sibling, 1 reply; 20+ messages in thread
From: Daniel Vetter @ 2016-12-02  7:53 UTC (permalink / raw)
  To: swati.dhingra; +Cc: intel-gfx, Sourab Gupta

On Thu, Dec 01, 2016 at 01:44:15PM +0530, swati.dhingra@intel.com wrote:
> 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>

I thought review feedback was to put that into drm, not under fs/? Also,
needs proper ccing.
-Daniel

> ---
>  drivers/gpu/drm/drm_drv.c  |   1 +
>  fs/Kconfig                 |   9 +
>  fs/Makefile                |   1 +
>  fs/drmfs/Makefile          |   3 +
>  fs/drmfs/inode.c           | 561 +++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/drmfs.h      |  56 +++++
>  include/uapi/linux/magic.h |   3 +
>  7 files changed, 634 insertions(+)
>  create mode 100644 fs/drmfs/Makefile
>  create mode 100644 fs/drmfs/inode.c
>  create mode 100644 include/linux/drmfs.h
> 
> 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..ac87e497
> --- /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..9220705
> --- /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
>  
> -- 
> 2.7.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 2/3] drm: Register drmfs filesystem from drm init
  2016-12-01  8:14 ` [RFC 2/3] drm: Register drmfs filesystem from drm init swati.dhingra
@ 2016-12-02  7:57   ` Daniel Vetter
  2016-12-02  8:32     ` sourab gupta
  0 siblings, 1 reply; 20+ messages in thread
From: Daniel Vetter @ 2016-12-02  7:57 UTC (permalink / raw)
  To: swati.dhingra; +Cc: intel-gfx, Sourab Gupta

On Thu, Dec 01, 2016 at 01:44:16PM +0530, swati.dhingra@intel.com wrote:
> From: Swati Dhingra <swati.dhingra@intel.com>
> 
> During drm module initialization, drm_core_init initializes the drmfs
> filesystem and register this with kernel. A driver specific directory is created
> inside drmfs root, and dentry of this directory is saved for subsequent use
> by the driver (e.g. i915). The driver can then create files/directories inside
> this root directory directly.
> In case of i915 driver, the top directory is created at '/sys/kernel/drm/i915'.
> 
> Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
> Signed-off-by: Swati Dhingra <swati.dhingra@intel.com>
> ---
>  drivers/gpu/drm/drm_drv.c | 22 ++++++++++++++++++++++
>  include/drm/drm_drv.h     |  3 +++
>  2 files changed, 25 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> index 84fcfcb..ead360bd 100644
> --- a/drivers/gpu/drm/drm_drv.c
> +++ b/drivers/gpu/drm/drm_drv.c
> @@ -688,6 +688,14 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
>  {
>  	int ret;
>  
> +#ifdef CONFIG_DRMFS
> +	dev->driver->drmfs_root = drmfs_create_dir(dev->driver->name, NULL);
> +	if (IS_ERR(dev->driver->drmfs_root)) {
> +		DRM_ERROR("Failed to get drmfs root dentry\n");
> +		return PTR_ERR(dev->driver->drmfs_root);
> +	}
> +#endif

Don't do #ifdef in the code, instead provide dummy static inline functions
that do nothing in headers when a feature is disabled. For an example see
CONFIG_DRM_FBDEV_EMULATION in drm_fb_helper.[hc].

Also, drmfs here is seriously lacking documentation. E.g. where are we
supposed to put different things related to rendering, modesetting, and
all these issues? You need to add a section in drm-uabi.rst, write
kernel-doc + overview sections for all of this and pull it in.
-Daniel

> +
>  	mutex_lock(&drm_global_mutex);
>  
>  	ret = drm_minor_register(dev, DRM_MINOR_CONTROL);
> @@ -758,6 +766,9 @@ void drm_dev_unregister(struct drm_device *dev)
>  	drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
>  	drm_minor_unregister(dev, DRM_MINOR_RENDER);
>  	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
> +#ifdef CONFIG_DRMFS
> +	drmfs_remove(dev->driver->drmfs_root);
> +#endif
>  }
>  EXPORT_SYMBOL(drm_dev_unregister);
>  
> @@ -825,6 +836,9 @@ static void drm_core_exit(void)
>  {
>  	unregister_chrdev(DRM_MAJOR, "drm");
>  	debugfs_remove(drm_debugfs_root);
> +#ifdef CONFIG_DRMFS
> +	drmfs_fini();
> +#endif
>  	drm_sysfs_destroy();
>  	idr_destroy(&drm_minors_idr);
>  	drm_connector_ida_destroy();
> @@ -845,6 +859,14 @@ static int __init drm_core_init(void)
>  		goto error;
>  	}
>  
> +#ifdef CONFIG_DRMFS
> +	ret = drmfs_init();
> +	if (ret < 0) {
> +		DRM_ERROR("Cannot create DRM FS: %d\n", ret);
> +		goto error;
> +	}
> +#endif
> +
>  	drm_debugfs_root = debugfs_create_dir("dri", NULL);
>  	if (!drm_debugfs_root) {
>  		ret = -ENOMEM;
> diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
> index aad8bba..34804de 100644
> --- a/include/drm/drm_drv.h
> +++ b/include/drm/drm_drv.h
> @@ -403,6 +403,9 @@ struct drm_driver {
>  
>  	/* List of devices hanging off this driver with stealth attach. */
>  	struct list_head legacy_dev_list;
> +
> +	/* drmfs parent directory dentry for this driver */
> +	struct dentry *drmfs_root;
>  };
>  
>  extern __printf(6, 7)
> -- 
> 2.7.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-02  7:53   ` Daniel Vetter
@ 2016-12-02  8:27     ` sourab gupta
  0 siblings, 0 replies; 20+ messages in thread
From: sourab gupta @ 2016-12-02  8:27 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, Dhingra, Swati

On Thu, 2016-12-01 at 23:53 -0800, Daniel Vetter wrote:
> On Thu, Dec 01, 2016 at 01:44:15PM +0530, swati.dhingra@intel.com wrote:
> > 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>
> 
> I thought review feedback was to put that into drm, not under fs/? Also,
> needs proper ccing.
> -Daniel
> 
Hi Daniel,
We'll remove it from fs and add under drm/ in the next version of
series. Sorry, forgot to add dri-devel, will add it when we send next
version.

> > ---
> >  drivers/gpu/drm/drm_drv.c  |   1 +
> >  fs/Kconfig                 |   9 +
> >  fs/Makefile                |   1 +
> >  fs/drmfs/Makefile          |   3 +
> >  fs/drmfs/inode.c           | 561 +++++++++++++++++++++++++++++++++++++++++++++
> >  include/linux/drmfs.h      |  56 +++++
> >  include/uapi/linux/magic.h |   3 +
> >  7 files changed, 634 insertions(+)
> >  create mode 100644 fs/drmfs/Makefile
> >  create mode 100644 fs/drmfs/inode.c
> >  create mode 100644 include/linux/drmfs.h
> > 
> > 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..ac87e497
> > --- /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..9220705
> > --- /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
> >  
> > -- 
> > 2.7.4
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 2/3] drm: Register drmfs filesystem from drm init
  2016-12-02  7:57   ` Daniel Vetter
@ 2016-12-02  8:32     ` sourab gupta
  0 siblings, 0 replies; 20+ messages in thread
From: sourab gupta @ 2016-12-02  8:32 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, Dhingra, Swati

On Thu, 2016-12-01 at 23:57 -0800, Daniel Vetter wrote:
> On Thu, Dec 01, 2016 at 01:44:16PM +0530, swati.dhingra@intel.com wrote:
> > From: Swati Dhingra <swati.dhingra@intel.com>
> > 
> > During drm module initialization, drm_core_init initializes the drmfs
> > filesystem and register this with kernel. A driver specific directory is created
> > inside drmfs root, and dentry of this directory is saved for subsequent use
> > by the driver (e.g. i915). The driver can then create files/directories inside
> > this root directory directly.
> > In case of i915 driver, the top directory is created at '/sys/kernel/drm/i915'.
> > 
> > Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
> > Signed-off-by: Swati Dhingra <swati.dhingra@intel.com>
> > ---
> >  drivers/gpu/drm/drm_drv.c | 22 ++++++++++++++++++++++
> >  include/drm/drm_drv.h     |  3 +++
> >  2 files changed, 25 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> > index 84fcfcb..ead360bd 100644
> > --- a/drivers/gpu/drm/drm_drv.c
> > +++ b/drivers/gpu/drm/drm_drv.c
> > @@ -688,6 +688,14 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
> >  {
> >  	int ret;
> >  
> > +#ifdef CONFIG_DRMFS
> > +	dev->driver->drmfs_root = drmfs_create_dir(dev->driver->name, NULL);
> > +	if (IS_ERR(dev->driver->drmfs_root)) {
> > +		DRM_ERROR("Failed to get drmfs root dentry\n");
> > +		return PTR_ERR(dev->driver->drmfs_root);
> > +	}
> > +#endif
> 
> Don't do #ifdef in the code, instead provide dummy static inline functions
> that do nothing in headers when a feature is disabled. For an example see
> CONFIG_DRM_FBDEV_EMULATION in drm_fb_helper.[hc].
> 
Sorry, Will take take of this going forward.

> Also, drmfs here is seriously lacking documentation. E.g. where are we
> supposed to put different things related to rendering, modesetting, and
> all these issues? You need to add a section in drm-uabi.rst, write
> kernel-doc + overview sections for all of this and pull it in.
> -Daniel
> 
Ok. Will work on adding requisite documentation for drmfs.

Thanks,
Sourab

> > +
> >  	mutex_lock(&drm_global_mutex);
> >  
> >  	ret = drm_minor_register(dev, DRM_MINOR_CONTROL);
> > @@ -758,6 +766,9 @@ void drm_dev_unregister(struct drm_device *dev)
> >  	drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
> >  	drm_minor_unregister(dev, DRM_MINOR_RENDER);
> >  	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
> > +#ifdef CONFIG_DRMFS
> > +	drmfs_remove(dev->driver->drmfs_root);
> > +#endif
> >  }
> >  EXPORT_SYMBOL(drm_dev_unregister);
> >  
> > @@ -825,6 +836,9 @@ static void drm_core_exit(void)
> >  {
> >  	unregister_chrdev(DRM_MAJOR, "drm");
> >  	debugfs_remove(drm_debugfs_root);
> > +#ifdef CONFIG_DRMFS
> > +	drmfs_fini();
> > +#endif
> >  	drm_sysfs_destroy();
> >  	idr_destroy(&drm_minors_idr);
> >  	drm_connector_ida_destroy();
> > @@ -845,6 +859,14 @@ static int __init drm_core_init(void)
> >  		goto error;
> >  	}
> >  
> > +#ifdef CONFIG_DRMFS
> > +	ret = drmfs_init();
> > +	if (ret < 0) {
> > +		DRM_ERROR("Cannot create DRM FS: %d\n", ret);
> > +		goto error;
> > +	}
> > +#endif
> > +
> >  	drm_debugfs_root = debugfs_create_dir("dri", NULL);
> >  	if (!drm_debugfs_root) {
> >  		ret = -ENOMEM;
> > diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
> > index aad8bba..34804de 100644
> > --- a/include/drm/drm_drv.h
> > +++ b/include/drm/drm_drv.h
> > @@ -403,6 +403,9 @@ struct drm_driver {
> >  
> >  	/* List of devices hanging off this driver with stealth attach. */
> >  	struct list_head legacy_dev_list;
> > +
> > +	/* drmfs parent directory dentry for this driver */
> > +	struct dentry *drmfs_root;
> >  };
> >  
> >  extern __printf(6, 7)
> > -- 
> > 2.7.4
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-01  8:14 ` [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces swati.dhingra
  2016-12-02  7:53   ` Daniel Vetter
@ 2016-12-02 22:40   ` Matt Roper
  2016-12-03  0:53     ` sourab gupta
  1 sibling, 1 reply; 20+ messages in thread
From: Matt Roper @ 2016-12-02 22:40 UTC (permalink / raw)
  To: swati.dhingra; +Cc: intel-gfx, Sourab Gupta

On Thu, Dec 01, 2016 at 01:44:15PM +0530, swati.dhingra@intel.com wrote:
> 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

Am I correct in assuming the data made available via drmfs is not
considered ABI?  If we're not going to guarantee a stable ABI and
backward compatibility forever for the items exposed here, then it's
important to state that very explicitly up front so that no userspace
software gets written with the wrong assumption.  I'd suggest making an
explicit note one way or the other in the commit message here and
probably in the Kconfig help text as well.


Matt

> 
> 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          |   3 +
>  fs/drmfs/inode.c           | 561 +++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/drmfs.h      |  56 +++++
>  include/uapi/linux/magic.h |   3 +
>  7 files changed, 634 insertions(+)
>  create mode 100644 fs/drmfs/Makefile
>  create mode 100644 fs/drmfs/inode.c
>  create mode 100644 include/linux/drmfs.h
> 
> 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..ac87e497
> --- /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..9220705
> --- /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
>  
> -- 
> 2.7.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-02 22:40   ` Matt Roper
@ 2016-12-03  0:53     ` sourab gupta
  2016-12-03  9:25       ` Chris Wilson
  0 siblings, 1 reply; 20+ messages in thread
From: sourab gupta @ 2016-12-03  0:53 UTC (permalink / raw)
  To: Roper, Matthew D; +Cc: intel-gfx, Dhingra, Swati

On Fri, 2016-12-02 at 14:40 -0800, Roper, Matthew D wrote:
> On Thu, Dec 01, 2016 at 01:44:15PM +0530, swati.dhingra@intel.com wrote:
> > 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
> 
> Am I correct in assuming the data made available via drmfs is not
> considered ABI?  If we're not going to guarantee a stable ABI and
> backward compatibility forever for the items exposed here, then it's
> important to state that very explicitly up front so that no userspace
> software gets written with the wrong assumption.  I'd suggest making an
> explicit note one way or the other in the commit message here and
> probably in the Kconfig help text as well.
> 
> 
> Matt
> 

We've intended for drmfs to be ABI as Chris mentioned here:
https://lists.freedesktop.org/archives/intel-gfx/2016-December/113245.html
The intent is for drmfs to be a stable ABI for the files it's holding.
This can be ensured moresoever since it'll be under sole control of drm.
Chris, can you correct me if i'm wrong.

-sourab
> > 
> > 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          |   3 +
> >  fs/drmfs/inode.c           | 561 +++++++++++++++++++++++++++++++++++++++++++++
> >  include/linux/drmfs.h      |  56 +++++
> >  include/uapi/linux/magic.h |   3 +
> >  7 files changed, 634 insertions(+)
> >  create mode 100644 fs/drmfs/Makefile
> >  create mode 100644 fs/drmfs/inode.c
> >  create mode 100644 include/linux/drmfs.h
> > 
> > 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..ac87e497
> > --- /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..9220705
> > --- /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
> >  
> > -- 
> > 2.7.4
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-03  0:53     ` sourab gupta
@ 2016-12-03  9:25       ` Chris Wilson
  0 siblings, 0 replies; 20+ messages in thread
From: Chris Wilson @ 2016-12-03  9:25 UTC (permalink / raw)
  To: sourab gupta; +Cc: intel-gfx, Dhingra, Swati

On Sat, Dec 03, 2016 at 06:23:20AM +0530, sourab gupta wrote:
> On Fri, 2016-12-02 at 14:40 -0800, Roper, Matthew D wrote:
> > Am I correct in assuming the data made available via drmfs is not
> > considered ABI?  If we're not going to guarantee a stable ABI and
> > backward compatibility forever for the items exposed here, then it's
> > important to state that very explicitly up front so that no userspace
> > software gets written with the wrong assumption.  I'd suggest making an
> > explicit note one way or the other in the commit message here and
> > probably in the Kconfig help text as well.
> 
> We've intended for drmfs to be ABI as Chris mentioned here:
> https://lists.freedesktop.org/archives/intel-gfx/2016-December/113245.html
> The intent is for drmfs to be a stable ABI for the files it's holding.
> This can be ensured moresoever since it'll be under sole control of drm.
> Chris, can you correct me if i'm wrong.

sysfs: stable ABI, one textual value per file
debugfs: unstable ABI, free-for-all

Proposed drmfs: stable ABI, free-for-all

Alternatives: ioctls, device nodes, netlink

ioctls: not as suitable to many single purpose continuous data
dumping, we would very quickly run out ioctl space; requires more
userspace support than "cat"

device nodes: a real possibilty, kernel instantiation is more tricky,
requires udev (+udev.rules) or userspace discovery of the dynamic
major:minor (via sysfs) [mounting a registered filesystem is easy in
comparison]

netlink: stream, copies, copies, copies.

In short, we have grown used to the convenience and flexibility in
presentation that debugfs gives us (including relayfs inodes) that we
want some of that hierachy in stable user ABI form.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-01  8:37     ` sourab gupta
@ 2016-12-01  8:58       ` Chris Wilson
  0 siblings, 0 replies; 20+ messages in thread
From: Chris Wilson @ 2016-12-01  8:58 UTC (permalink / raw)
  To: sourab gupta; +Cc: intel-gfx, Dhingra, Swati

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

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-01  8:31     ` sourab gupta
@ 2016-12-01  8:48       ` Chris Wilson
  0 siblings, 0 replies; 20+ messages in thread
From: Chris Wilson @ 2016-12-01  8:48 UTC (permalink / raw)
  To: sourab gupta; +Cc: intel-gfx, Dhingra, Swati

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, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-01  8:11   ` Chris Wilson
@ 2016-12-01  8:37     ` sourab gupta
  2016-12-01  8:58       ` Chris Wilson
  0 siblings, 1 reply; 20+ messages in thread
From: sourab gupta @ 2016-12-01  8:37 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx, Dhingra, Swati

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?

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-01  8:07   ` Chris Wilson
@ 2016-12-01  8:31     ` sourab gupta
  2016-12-01  8:48       ` Chris Wilson
  0 siblings, 1 reply; 20+ messages in thread
From: sourab gupta @ 2016-12-01  8:31 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx, Dhingra, Swati

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?



_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-01  7:02 ` [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces swati.dhingra
  2016-12-01  8:07   ` Chris Wilson
@ 2016-12-01  8:11   ` Chris Wilson
  2016-12-01  8:37     ` sourab gupta
  1 sibling, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2016-12-01  8:11 UTC (permalink / raw)
  To: swati.dhingra; +Cc: intel-gfx, Sourab Gupta

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

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-01  7:02 ` [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces swati.dhingra
@ 2016-12-01  8:07   ` Chris Wilson
  2016-12-01  8:31     ` sourab gupta
  2016-12-01  8:11   ` Chris Wilson
  1 sibling, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2016-12-01  8:07 UTC (permalink / raw)
  To: swati.dhingra; +Cc: intel-gfx, Sourab Gupta

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, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces
  2016-12-01  7:02 swati.dhingra
@ 2016-12-01  7:02 ` swati.dhingra
  2016-12-01  8:07   ` Chris Wilson
  2016-12-01  8:11   ` Chris Wilson
  0 siblings, 2 replies; 20+ messages in thread
From: swati.dhingra @ 2016-12-01  7:02 UTC (permalink / raw)
  To: intel-gfx; +Cc: Sourab Gupta, Swati Dhingra

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

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
 
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2016-12-03  9:25 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-01  8:14 [RFC 0/3] Introduce drmfs pseudo filesystem for drm subsystem swati.dhingra
2016-12-01  8:14 ` [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces swati.dhingra
2016-12-02  7:53   ` Daniel Vetter
2016-12-02  8:27     ` sourab gupta
2016-12-02 22:40   ` Matt Roper
2016-12-03  0:53     ` sourab gupta
2016-12-03  9:25       ` Chris Wilson
2016-12-01  8:14 ` [RFC 2/3] drm: Register drmfs filesystem from drm init swati.dhingra
2016-12-02  7:57   ` Daniel Vetter
2016-12-02  8:32     ` sourab gupta
2016-12-01  8:14 ` [RFC 3/3] drm/i915: Creating guc log file in drmfs instead of debugfs swati.dhingra
2016-12-01  8:45 ` ✓ Fi.CI.BAT: success for Introduce drmfs pseudo filesystem for drm subsystem (rev2) Patchwork
2016-12-02  7:52 ` [RFC 0/3] Introduce drmfs pseudo filesystem for drm subsystem Daniel Vetter
  -- strict thread matches above, loose matches on Subject: below --
2016-12-01  7:02 swati.dhingra
2016-12-01  7:02 ` [RFC 1/3] fs: Introduce drmfs pseudo filesystem interfaces swati.dhingra
2016-12-01  8:07   ` Chris Wilson
2016-12-01  8:31     ` sourab gupta
2016-12-01  8:48       ` Chris Wilson
2016-12-01  8:11   ` Chris Wilson
2016-12-01  8:37     ` sourab gupta
2016-12-01  8:58       ` Chris Wilson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.