]> git.karo-electronics.de Git - linux-beck.git/commitdiff
drm/i915: Add per client max context ban limit
authorMika Kuoppala <mika.kuoppala@linux.intel.com>
Fri, 18 Nov 2016 13:10:47 +0000 (15:10 +0200)
committerMika Kuoppala <mika.kuoppala@intel.com>
Mon, 21 Nov 2016 12:36:40 +0000 (14:36 +0200)
If we have a bad client submitting unfavourably across different
contexts, creating new ones, the per context scoring of badness
doesn't remove the root cause, the offending client.
To counter, keep track of per client context bans. Deny access if
client is responsible for more than 3 context bans in
it's lifetime.

v2: move ban check to context create ioctl (Chris)
v3: add commentary about hangs needed to reach client ban (Chris)

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com>
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gpu_error.c

index 7db7b37937e7d483c13e8fff0d3af9418d7f8cef..1f0b5c37f6de493356b5f248b06a0ea9a9d3fac3 100644 (file)
@@ -416,6 +416,15 @@ struct drm_i915_file_private {
        } rps;
 
        unsigned int bsd_engine;
+
+/* Client can have a maximum of 3 contexts banned before
+ * it is denied of creating new contexts. As one context
+ * ban needs 4 consecutive hangs, and more if there is
+ * progress in between, this is a last resort stop gap measure
+ * to limit the badly behaving clients access to gpu.
+ */
+#define I915_MAX_CLIENT_CONTEXT_BANS 3
+       int context_bans;
 };
 
 /* Used by dp and fdi links */
@@ -872,6 +881,7 @@ struct drm_i915_error_state {
 
                pid_t pid;
                char comm[TASK_COMM_LEN];
+               int context_bans;
        } engine[I915_NUM_ENGINES];
 
        struct drm_i915_error_buffer {
index 99198146ecc86f067476d9c57abf7c7285bb7d88..a8118386a23b9dc081f3610e1994cff4ee214ec0 100644 (file)
@@ -2646,6 +2646,20 @@ static void i915_gem_context_mark_guilty(struct i915_gem_context *ctx)
 
        hs->banned = i915_context_is_banned(ctx);
        hs->batch_active++;
+
+       DRM_DEBUG_DRIVER("context %s marked guilty (score %d) banned? %s\n",
+                        ctx->name, hs->ban_score, yesno(hs->banned));
+
+       if (!ctx->file_priv)
+               return;
+
+       if (hs->banned) {
+               ctx->file_priv->context_bans++;
+
+               DRM_DEBUG_DRIVER("client %s has has %d context banned\n",
+                                ctx->name,
+                                ctx->file_priv->context_bans);
+       }
 }
 
 static void i915_gem_context_mark_innocent(struct i915_gem_context *ctx)
index 97012373a8d57080b879539127d5e8d74ed22517..88d59866c4339ea2e726ec3416d3d69282c8dce7 100644 (file)
@@ -1003,6 +1003,11 @@ static bool contexts_enabled(struct drm_device *dev)
        return i915.enable_execlists || to_i915(dev)->hw_context_size;
 }
 
+static bool client_is_banned(struct drm_i915_file_private *file_priv)
+{
+       return file_priv->context_bans > I915_MAX_CLIENT_CONTEXT_BANS;
+}
+
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
                                  struct drm_file *file)
 {
@@ -1017,6 +1022,14 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
        if (args->pad != 0)
                return -EINVAL;
 
+       if (client_is_banned(file_priv)) {
+               DRM_DEBUG("client %s[%d] banned from creating ctx\n",
+                         current->comm,
+                         pid_nr(get_task_pid(current, PIDTYPE_PID)));
+
+               return -EIO;
+       }
+
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                return ret;
index fa988a00ae68b11e53054f4853a81fa7abf39bb0..af4f0ef4fa08fa7d32602e2b9e5b65d4c70bc303 100644 (file)
@@ -538,10 +538,11 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
        for (i = 0; i < ARRAY_SIZE(error->engine); i++) {
                if (error->engine[i].hangcheck_stalled &&
                    error->engine[i].pid != -1) {
-                       err_printf(m, "Active process (on ring %s): %s [%d]\n",
+                       err_printf(m, "Active process (on ring %s): %s [%d], context bans %d\n",
                                   engine_str(i),
                                   error->engine[i].comm,
-                                  error->engine[i].pid);
+                                  error->engine[i].pid,
+                                  error->engine[i].context_bans);
                }
        }
        err_printf(m, "Reset count: %u\n", error->reset_count);
@@ -632,9 +633,10 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                if (obj) {
                        err_puts(m, dev_priv->engine[i]->name);
                        if (ee->pid != -1)
-                               err_printf(m, " (submitted by %s [%d])",
+                               err_printf(m, " (submitted by %s [%d], bans %d)",
                                           ee->comm,
-                                          ee->pid);
+                                          ee->pid,
+                                          ee->context_bans);
                        err_printf(m, " --- gtt_offset = 0x%08x %08x\n",
                                   upper_32_bits(obj->gtt_offset),
                                   lower_32_bits(obj->gtt_offset));