Introduce a new DRM_IOCTL_I915_CGROUP_SETPARAM ioctl that will allow userspace to set i915-specific parameters for individual cgroups. i915 cgroup data will be registered and later looked up via the new cgroup_priv infrastructure. v2: - Large rebase/rewrite for new cgroup_priv interface v3: - Another rebase/rewrite for ida-based keys and kref-based storage - Access control no longer follows cgroup filesystem permissions; instead we restrict access to either DRM master or capable(CAP_SYS_RESOURCE). v4: - Fix checkpatch warnings (Intel CI) Signed-off-by: Matt Roper <matthew.d.roper@xxxxxxxxx> --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_cgroup.c | 140 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.c | 8 +++ drivers/gpu/drm/i915/i915_drv.h | 32 +++++++++ include/uapi/drm/i915_drm.h | 12 ++++ 5 files changed, 193 insertions(+) create mode 100644 drivers/gpu/drm/i915/i915_cgroup.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 552e43e9663f..26031185cf0e 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -48,6 +48,7 @@ i915-y := i915_drv.o \ i915-$(CONFIG_COMPAT) += i915_ioc32.o i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o intel_pipe_crc.o i915-$(CONFIG_PERF_EVENTS) += i915_pmu.o +i915-$(CONFIG_CGROUPS) += i915_cgroup.o # GEM code i915-y += i915_cmd_parser.o \ diff --git a/drivers/gpu/drm/i915/i915_cgroup.c b/drivers/gpu/drm/i915/i915_cgroup.c new file mode 100644 index 000000000000..efe76c2a8915 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_cgroup.c @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: MIT */ +/* + * i915_cgroup.c - Linux cgroups integration for i915 + * + * Copyright (C) 2018 Intel Corporation + */ + +#include <linux/cgroup.h> + +#include "i915_drv.h" + +struct i915_cgroup_data { + struct kref ref; +}; + +static inline struct i915_cgroup_data * +cgrp_ref_to_i915(struct kref *ref) +{ + return container_of(ref, struct i915_cgroup_data, ref); +} + +static void +i915_cgroup_free(struct kref *ref) +{ + struct i915_cgroup_data *priv; + + priv = cgrp_ref_to_i915(ref); + kfree(priv); +} + +int +i915_cgroup_init(struct drm_i915_private *dev_priv) +{ + int ret = 0; + + dev_priv->cgroup_priv_key = cgroup_priv_getkey(i915_cgroup_free); + if (dev_priv->cgroup_priv_key < 0) { + DRM_DEBUG_DRIVER("Failed to get a cgroup private data key\n"); + ret = dev_priv->cgroup_priv_key; + } + + mutex_init(&dev_priv->cgroup_lock); + + return ret; +} + +void +i915_cgroup_shutdown(struct drm_i915_private *dev_priv) +{ + cgroup_priv_destroykey(dev_priv->cgroup_priv_key); +} + +/* + * Return i915 cgroup private data, creating and registering it if one doesn't + * already exist for this cgroup. + */ +__maybe_unused +static struct i915_cgroup_data * +get_or_create_cgroup_data(struct drm_i915_private *dev_priv, + struct cgroup *cgrp) +{ + struct kref *ref; + struct i915_cgroup_data *priv; + + mutex_lock(&dev_priv->cgroup_lock); + + ref = cgroup_priv_get(cgrp, dev_priv->cgroup_priv_key); + if (ref) { + priv = cgrp_ref_to_i915(ref); + } else { + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + priv = ERR_PTR(-ENOMEM); + goto out; + } + + kref_init(&priv->ref); + cgroup_priv_install(cgrp, dev_priv->cgroup_priv_key, + &priv->ref); + } + +out: + mutex_unlock(&dev_priv->cgroup_lock); + + return priv; +} + +/** + * i915_cgroup_setparam_ioctl - ioctl to alter i915 settings for a cgroup + * @dev: DRM device + * @data: data pointer for the ioctl + * @file_priv: DRM file handle for the ioctl call + * + * Allows i915-specific parameters to be set for a Linux cgroup. + */ +int +i915_cgroup_setparam_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file) +{ + struct drm_i915_cgroup_param *req = data; + struct cgroup *cgrp; + int ret; + + /* We don't actually support any flags yet. */ + if (req->flags) { + DRM_DEBUG_DRIVER("Invalid flags\n"); + return -EINVAL; + } + + /* + * Make sure the file descriptor really is a cgroup fd and is on the + * v2 hierarchy. + */ + cgrp = cgroup_get_from_fd(req->cgroup_fd); + if (IS_ERR(cgrp)) { + DRM_DEBUG_DRIVER("Invalid cgroup file descriptor\n"); + return PTR_ERR(cgrp); + } + + /* + * Access control: For now we grant access via CAP_SYS_RESOURCE _or_ + * DRM master status. + */ + if (!capable(CAP_SYS_RESOURCE) && !drm_is_current_master(file)) { + DRM_DEBUG_DRIVER("Insufficient permissions to adjust i915 cgroup settings\n"); + goto out; + } + + switch (req->param) { + default: + DRM_DEBUG_DRIVER("Invalid cgroup parameter %lld\n", req->param); + ret = -EINVAL; + } + +out: + cgroup_put(cgrp); + + return ret; +} diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a7d3275f45d2..ad10fb2a2907 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1407,6 +1407,10 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent) intel_runtime_pm_put(dev_priv); + ret = i915_cgroup_init(dev_priv); + if (ret < 0) + goto out_cleanup_hw; + i915_welcome_messages(dev_priv); return 0; @@ -1433,6 +1437,8 @@ void i915_driver_unload(struct drm_device *dev) struct drm_i915_private *dev_priv = to_i915(dev); struct pci_dev *pdev = dev_priv->drm.pdev; + i915_cgroup_shutdown(dev_priv); + i915_driver_unregister(dev_priv); if (i915_gem_suspend(dev_priv)) @@ -2833,6 +2839,8 @@ static const struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_PERF_ADD_CONFIG, i915_perf_add_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_PERF_REMOVE_CONFIG, i915_perf_remove_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_QUERY, i915_query_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_CGROUP_SETPARAM, i915_cgroup_setparam_ioctl, + DRM_UNLOCKED | DRM_RENDER_ALLOW), }; static struct drm_driver driver = { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2d7a89fcc0dc..ed365fae1073 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1738,6 +1738,15 @@ struct drm_i915_private { struct intel_ppat ppat; + /* cgroup private data */ + int cgroup_priv_key; + + /* + * protects against concurrent attempts to create private data for a + * cgroup + */ + struct mutex cgroup_lock; + /* Kernel Modesetting */ struct intel_crtc *plane_to_crtc_mapping[I915_MAX_PIPES]; @@ -2678,6 +2687,29 @@ intel_ggtt_update_needs_vtd_wa(struct drm_i915_private *dev_priv) int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv, int enable_ppgtt); +/* i915_cgroup.c */ +#ifdef CONFIG_CGROUPS +int i915_cgroup_init(struct drm_i915_private *dev_priv); +int i915_cgroup_setparam_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); +void i915_cgroup_shutdown(struct drm_i915_private *dev_priv); +#else +static inline int +i915_cgroup_init(struct drm_i915_private *dev_priv) +{ + return 0; +} + +static inline void i915_cgroup_shutdown(struct drm_i915_private *dev_priv) {} + +static inline int +i915_cgroup_setparam_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + return -EINVAL; +} +#endif + /* i915_drv.c */ void __printf(3, 4) __i915_printk(struct drm_i915_private *dev_priv, const char *level, diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 7f5634ce8e88..735128fa61de 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -319,6 +319,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_PERF_ADD_CONFIG 0x37 #define DRM_I915_PERF_REMOVE_CONFIG 0x38 #define DRM_I915_QUERY 0x39 +#define DRM_I915_CGROUP_SETPARAM 0x3a #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -377,6 +378,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_PERF_ADD_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config) #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64) #define DRM_IOCTL_I915_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query) +#define DRM_IOCTL_I915_CGROUP_SETPARAM DRM_IOW(DRM_COMMAND_BASE + DRM_I915_CGROUP_SETPARAM, struct drm_i915_cgroup_param) /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. @@ -1717,6 +1719,16 @@ struct drm_i915_query_topology_info { __u8 data[]; }; +/** + * Structure to set i915 parameter on a cgroup. + */ +struct drm_i915_cgroup_param { + __s32 cgroup_fd; + __u32 flags; + __u64 param; + __s64 value; +}; + #if defined(__cplusplus) } #endif -- 2.14.3 -- To unsubscribe from this list: send the line "unsubscribe cgroups" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html