@@ -669,6 +669,16 @@ struct drm_driver {
void (*drmcg_custom_init)(struct drm_device *dev,
struct drmcg_props *props);
+ /**
+ * @drmcg_limit_updated
+ *
+ * Optional callback
+ */
+ void (*drmcg_limit_updated)(struct drm_device *dev,
+ struct task_struct *task,\
+ struct drmcg_device_resource *ddr,
+ enum drmcg_res_type res_type);
+
/**
* @gem_vm_ops: Driver private ops for this object
*/
@@ -621,6 +621,23 @@ static void drmcg_nested_limit_parse(struct kernfs_open_file *of,
}
}
+static void drmcg_limit_updated(struct drm_device *dev, struct drmcg *drmcg,
+ enum drmcg_res_type res_type)
+{
+ struct drmcg_device_resource *ddr =
+ drmcg->dev_resources[dev->primary->index];
+ struct css_task_iter it;
+ struct task_struct *task;
+
+ css_task_iter_start(&drmcg->css.cgroup->self,
+ CSS_TASK_ITER_PROCS, &it);
+ while ((task = css_task_iter_next(&it))) {
+ dev->driver->drmcg_limit_updated(dev, task,
+ ddr, res_type);
+ }
+ css_task_iter_end(&it);
+}
+
static ssize_t drmcg_limit_write(struct kernfs_open_file *of, char *buf,
size_t nbytes, loff_t off)
{
@@ -726,6 +743,10 @@ static ssize_t drmcg_limit_write(struct kernfs_open_file *of, char *buf,
default:
break;
}
+
+ if (dm->dev->driver->drmcg_limit_updated)
+ drmcg_limit_updated(dm->dev, drmcg, type);
+
drm_dev_put(dm->dev); /* release from drm_minor_acquire */
}
@@ -863,9 +884,45 @@ struct cftype files[] = {
{ } /* terminate */
};
+static int drmcg_attach_fn(int id, void *ptr, void *data)
+{
+ struct drm_minor *minor = ptr;
+ struct task_struct *task = data;
+ struct drm_device *dev;
+
+ if (minor->type != DRM_MINOR_PRIMARY)
+ return 0;
+
+ dev = minor->dev;
+
+ if (dev->driver->drmcg_limit_updated) {
+ struct drmcg *drmcg = drmcg_get(task);
+ struct drmcg_device_resource *ddr =
+ drmcg->dev_resources[minor->index];
+ enum drmcg_res_type type;
+
+ for (type = 0; type < __DRMCG_TYPE_LAST; type++)
+ dev->driver->drmcg_limit_updated(dev, task, ddr, type);
+
+ drmcg_put(drmcg);
+ }
+
+ return 0;
+}
+
+static void drmcg_attach(struct cgroup_taskset *tset)
+{
+ struct task_struct *task;
+ struct cgroup_subsys_state *css;
+
+ cgroup_taskset_for_each(task, css, tset)
+ drm_minor_for_each(&drmcg_attach_fn, task);
+}
+
struct cgroup_subsys drm_cgrp_subsys = {
.css_alloc = drmcg_css_alloc,
.css_free = drmcg_css_free,
+ .attach = drmcg_attach,
.early_init = false,
.legacy_cftypes = files,
.dfl_cftypes = files,
Before this commit, drmcg limits are updated but enforcement is delayed until the next time the driver check against the new limit. While this is sufficient for certain resources, a more proactive enforcement may be needed for other resources. Introducing an optional drmcg_limit_updated callback for the DRM drivers. When defined, it will be called in two scenarios: 1) When limits are updated for a particular cgroup, the callback will be triggered for each task in the updated cgroup. 2) When a task is migrated from one cgroup to another, the callback will be triggered for each resource type for the migrated task. Change-Id: I68187a72818b855b5f295aefcb241cda8ab63b00 Signed-off-by: Kenny Ho <Kenny.Ho@amd.com> --- include/drm/drm_drv.h | 10 ++++++++ kernel/cgroup/drm.c | 57 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+)