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 Signed-off-by: Matt Roper <matthew.d.roper@xxxxxxxxx> --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_cgroup.c | 167 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.c | 5 ++ drivers/gpu/drm/i915/i915_drv.h | 24 ++++++ include/uapi/drm/i915_drm.h | 12 +++ 5 files changed, 209 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 1bd9bc5b8c5c..5974e32834bf 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..4a46cb167f53 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_cgroup.c @@ -0,0 +1,167 @@ +/* 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 cgroup_priv base; + + struct list_head node; +}; + +static inline struct i915_cgroup_data * +cgrp_to_i915(struct cgroup_priv *priv) +{ + return container_of(priv, struct i915_cgroup_data, base); +} + +static void +i915_cgroup_free(struct cgroup_priv *priv) +{ + struct cgroup *cgrp = priv->cgroup; + struct i915_cgroup_data *ipriv; + + WARN_ON(!mutex_is_locked(&cgrp->privdata_mutex)); + + ipriv = cgrp_to_i915(priv); + + /* + * Remove private data from both cgroup's hashtable and i915's list. + * If this function is being called as a result of cgroup removal + * (as opposed to an i915 unload), it will have already been removed from + * the hashtable, but the hash_del() call here is still safe. + */ + hash_del(&priv->hnode); + list_del(&ipriv->node); + + kfree(ipriv); +} + +void +i915_cgroup_init(struct drm_i915_private *dev_priv) +{ + INIT_LIST_HEAD(&dev_priv->cgroup_list); +} + +void +i915_cgroup_shutdown(struct drm_i915_private *dev_priv) +{ + struct i915_cgroup_data *priv, *tmp; + struct cgroup *cgrp; + + mutex_lock(&cgroup_mutex); + + list_for_each_entry_safe(priv, tmp, &dev_priv->cgroup_list, node) { + cgrp = priv->base.cgroup; + + mutex_lock(&cgrp->privdata_mutex); + i915_cgroup_free(&priv->base); + mutex_unlock(&cgrp->privdata_mutex); + } + + mutex_unlock(&cgroup_mutex); +} + +/* + * Return i915 cgroup private data, creating and registering it if one doesn't + * already exist for this cgroup. + */ +static struct i915_cgroup_data * +get_or_create_cgroup_data(struct drm_i915_private *dev_priv, + struct cgroup *cgrp) +{ + struct cgroup_priv *priv; + struct i915_cgroup_data *ipriv; + + mutex_lock(&cgrp->privdata_mutex); + + priv = cgroup_priv_lookup(cgrp, dev_priv); + if (priv) { + ipriv = cgrp_to_i915(priv); + } else { + ipriv = kzalloc(sizeof *ipriv, GFP_KERNEL); + if (!ipriv) { + ipriv = ERR_PTR(-ENOMEM); + goto out; + } + + ipriv->base.key = dev_priv; + ipriv->base.free = i915_cgroup_free; + list_add(&ipriv->node, &dev_priv->cgroup_list); + + cgroup_priv_install(cgrp, &ipriv->base); + } + +out: + mutex_unlock(&cgrp->privdata_mutex); + + return ipriv; +} + +/** + * 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: 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). + */ + ret = cgroup_permission(req->cgroup_fd, MAY_WRITE); + if (ret) + 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 d61b51c0bf0b..a1c7bc9cd173 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1405,6 +1405,8 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent) intel_runtime_pm_put(dev_priv); + i915_cgroup_init(dev_priv); + i915_welcome_messages(dev_priv); return 0; @@ -1431,6 +1433,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)) @@ -2832,6 +2836,7 @@ static const struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_PERF_OPEN, i915_perf_open_ioctl, DRM_RENDER_ALLOW), 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_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 7eec99d7fad4..7c38142ee009 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2006,6 +2006,9 @@ struct drm_i915_private { struct intel_ppat ppat; + /* cgroup private data */ + struct list_head cgroup_list; + /* Kernel Modesetting */ struct intel_crtc *plane_to_crtc_mapping[I915_MAX_PIPES]; @@ -2938,6 +2941,27 @@ 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 +void 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 29fa48e4755d..b6651b263838 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -318,6 +318,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_PERF_OPEN 0x36 #define DRM_I915_PERF_ADD_CONFIG 0x37 #define DRM_I915_PERF_REMOVE_CONFIG 0x38 +#define DRM_I915_CGROUP_SETPARAM 0x39 #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) @@ -375,6 +376,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_PERF_OPEN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param) #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_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. @@ -1615,6 +1617,16 @@ struct drm_i915_perf_oa_config { __u64 flex_regs_ptr; }; +/** + * 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