diff mbox

[RFC,5/9] drm: Introduce DRM_IOCTL_CGROUP_SETPARAM

Message ID 20180120015141.10118-6-matthew.d.roper@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Matt Roper Jan. 20, 2018, 1:51 a.m. UTC
cgroups are a convenient mechanism for system integrators to organize processes
into a logical hierarchy for system configuration purposes.  cgroups can be
used to control resources (memory, cpu time share, etc.) or apply other types
of subsystem-specific policy (network priorty, BPF programs, etc.) to subsets
of processes.

The DRM subsystem manages several concepts that would be good candidates for
exposure and control via the existing cgroup hierarchy --- GPU priorities for
sets of applications, limits on discrete or stolen video memories, etc.  Let's
add a 'setparam' ioctl to the DRM subsystem that allows a userspace tool to
set parameters on a cgroup for use by a DRM driver.

DRM cgroup parameters are a (u64 param, s64 value) pair associated with a
cgroup for a specific drm_device.  In the future there may potentially be both
driver-specific parameters as well as common parameters supported by all DRM
drivers.  We define parameter keys 0-0xFFFFFF as being driver-specific
parameters and reserve all higher keys for DRM core use.

Cc: Tejun Heo <tj@kernel.org>
Cc: cgroups@vger.kernel.org
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/Makefile     |   1 +
 drivers/gpu/drm/drm_cgroup.c | 120 +++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_ioctl.c  |   5 ++
 include/drm/drm_cgroup.h     |  38 ++++++++++++++
 include/drm/drm_device.h     |   8 +++
 include/uapi/drm/drm.h       |  10 ++++
 6 files changed, 182 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_cgroup.c
 create mode 100644 include/drm/drm_cgroup.h
diff mbox

Patch

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index dd5ae67f8e2b..351f3817bc27 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -30,6 +30,7 @@  drm-$(CONFIG_OF) += drm_of.o
 drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
 drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
+drm-$(CONFIG_CGROUPS) += drm_cgroup.o
 
 drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
 		drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
diff --git a/drivers/gpu/drm/drm_cgroup.c b/drivers/gpu/drm/drm_cgroup.c
new file mode 100644
index 000000000000..0d9187ee435d
--- /dev/null
+++ b/drivers/gpu/drm/drm_cgroup.c
@@ -0,0 +1,120 @@ 
+/*
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_cgroup.h>
+
+/**
+ * DOC: cgroup handling
+ *
+ * cgroups are a core kernel mechanism for organizing OS processes into logical
+ * groupings to which policy configuration or resource management may be
+ * applied.  Some DRM drivers may control resources or have policy settings
+ * that a system integrator would wish to configure according to the system
+ * cgroups hierarchy.  To support such use cases, the DRM framework allows
+ * drivers to track 'parameters' on a per-cgroup basis.  Parameters are a (u64
+ * key, s64 value) pair which would generally be set on specific cgroups
+ * during system configuration (e.g., by a sysv init script or systemd service)
+ * and then used by the driver at runtime to manage GPU-specific resources or
+ * control driver-specific policy.
+ */
+
+/**
+ * drm_cgroup_setparam_ioctl
+ * @dev: DRM device
+ * @data: data pointer for the ioctl
+ * @file_priv: DRM file handle for the ioctl call
+ *
+ * Set DRM-specific parameters for a cgroup
+ */
+int
+drm_cgroup_setparam_ioctl(struct drm_device *dev, void *data,
+			  struct drm_file *file_priv)
+{
+	struct drm_cgroup_setparam *req = data;
+	struct cgroup *cgrp;
+	struct file *f;
+	struct inode *inode = NULL;
+	int ret;
+
+	/*
+	 * We'll let drivers create their own parameters with ID's from
+	 * 0-0xFFFFFF.  We'll reserve parameter ID's above that range for
+	 * anything the DRM core wants to control directly; today we don't
+	 * have any such core-managed parameters, so just reject attempts
+	 * to set a cgroup parameter in this range.
+	 */
+	if (req->param > DRM_CGROUP_MAX_DRIVER_PARAM) {
+		DRM_DEBUG("Invalid cgroup parameter ID\n");
+		return -EINVAL;
+	}
+
+	if (!dev->cgroup) {
+		DRM_DEBUG("Invalid cgroup parameter ID\n");
+		return -EINVAL;
+	}
+
+	/* Make sure the file descriptor really is a cgroup fd */
+	cgrp = cgroup_get_from_fd(req->cgroup_fd);
+	if (IS_ERR(cgrp)) {
+		DRM_DEBUG("Invalid cgroup file descriptor\n");
+		return PTR_ERR(cgrp);
+	}
+
+	/*
+	 * Restrict this functionality to cgroups on the cgroups-v2
+	 * (i.e., default) hierarchy.
+	 */
+	if (!cgroup_on_dfl(cgrp)) {
+		DRM_DEBUG("setparam only supported on cgroup-v2 hierarchy\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Access control:  The strategy for using cgroups in a given
+	 * environment is generally determined by the system integrator
+	 * and/or OS vendor, so the specific policy about who can/can't
+	 * manipulate them tends to be domain-specific (and may vary
+	 * depending on the location in the cgroup hierarchy).  Rather than
+	 * trying to tie permission on this ioctl to a DRM-specific concepts
+	 * like DRM master, we'll allow cgroup parameters to be set by any
+	 * process that has been granted write access on the cgroup's
+	 * virtual file system (i.e., the same permissions that would
+	 * generally be needed to update the virtual files provided by
+	 * cgroup controllers).
+	 */
+	f = fget_raw(req->cgroup_fd);
+	if (WARN_ON(!f))
+		return -EBADF;
+
+	inode = kernfs_get_inode(f->f_path.dentry->d_sb, cgrp->kn);
+	if (inode)
+		ret = inode_permission(inode, MAY_WRITE);
+	else
+		ret = -ENOMEM;
+
+	iput(inode);
+	fput(f);
+
+	return ret ?: dev->cgroup->set_param(dev, cgrp, req->param,
+					     req->value);
+}
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index b1e96fb68ea8..d457a012427c 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -31,6 +31,7 @@ 
 #include <drm/drm_ioctl.h>
 #include <drm/drmP.h>
 #include <drm/drm_auth.h>
+#include <drm/drm_cgroup.h>
 #include "drm_legacy.h"
 #include "drm_internal.h"
 #include "drm_crtc_internal.h"
@@ -549,6 +550,10 @@  static const struct drm_ioctl_desc drm_ioctls[] = {
 	DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_UNLOCKED | DRM_MASTER),
+#if IS_ENABLED(CONFIG_CGROUPS)
+	DRM_IOCTL_DEF(DRM_IOCTL_CGROUP_SETPARAM, drm_cgroup_setparam_ioctl,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+#endif
 
 	DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 	DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
diff --git a/include/drm/drm_cgroup.h b/include/drm/drm_cgroup.h
new file mode 100644
index 000000000000..b43b6e5b4222
--- /dev/null
+++ b/include/drm/drm_cgroup.h
@@ -0,0 +1,38 @@ 
+/*
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __DRM_CGROUP_H__
+
+#include <linux/cgroup.h>
+#include <drm/drm_file.h>
+
+struct drm_cgroup_funcs {
+	int (*set_param)(struct drm_device *dev,
+			 struct cgroup *cgrp,
+			 uint64_t param,
+			 int64_t val);
+};
+
+int drm_cgroup_setparam_ioctl(struct drm_device *dev, void *data,
+			      struct drm_file *file_priv);
+
+#endif
diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
index 7c4fa32f3fc6..6eee7bbee602 100644
--- a/include/drm/drm_device.h
+++ b/include/drm/drm_device.h
@@ -18,6 +18,7 @@  struct drm_sg_mem;
 struct drm_local_map;
 struct drm_vma_offset_manager;
 struct drm_fb_helper;
+struct drm_cgroup_funcs;
 
 struct inode;
 
@@ -194,6 +195,13 @@  struct drm_device {
 	 * Set by drm_fb_helper_init() and cleared by drm_fb_helper_fini().
 	 */
 	struct drm_fb_helper *fb_helper;
+
+#ifdef CONFIG_CGROUPS
+	/**
+	 * @cgroup: Per-driver cgroup handlers.
+	 */
+	struct drm_cgroup_funcs *cgroup;
+#endif /* CONFIG_CGROUPS */
 };
 
 #endif
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 6fdff5945c8a..1caa1ce446e7 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -686,6 +686,15 @@  struct drm_set_client_cap {
 	__u64 value;
 };
 
+/** DRM_IOCTL_CGROUP_SETPARAM ioctl argument type */
+struct drm_cgroup_setparam {
+	__s32 cgroup_fd;
+	__u32 reserved;
+	__u64 param;
+	__s64 value;
+};
+#define DRM_CGROUP_MAX_DRIVER_PARAM  0xFFFFFF
+
 #define DRM_RDWR O_RDWR
 #define DRM_CLOEXEC O_CLOEXEC
 struct drm_prime_handle {
@@ -789,6 +798,7 @@  extern "C" {
 #define DRM_IOCTL_GEM_OPEN		DRM_IOWR(0x0b, struct drm_gem_open)
 #define DRM_IOCTL_GET_CAP		DRM_IOWR(0x0c, struct drm_get_cap)
 #define DRM_IOCTL_SET_CLIENT_CAP	DRM_IOW( 0x0d, struct drm_set_client_cap)
+#define DRM_IOCTL_CGROUP_SETPARAM	DRM_IOW( 0x0e, struct drm_cgroup_setparam)
 
 #define DRM_IOCTL_SET_UNIQUE		DRM_IOW( 0x10, struct drm_unique)
 #define DRM_IOCTL_AUTH_MAGIC		DRM_IOW( 0x11, struct drm_auth)