You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
drm/i915: Cache the error string
Currently, we convert the error state into a string every time we read from sysfs (and sysfs reads in page size (4KiB) chunks). We do try to window the string and only capture the portion that is being read, but that means that we must always convert up to the window to find the start. For a very large error state bordering on EXEC_OBJECT_CAPTURE abuse, this is noticeable as it degrades to O(N^2)! As we do not have a convenient hook for sysfs open(), and we would like to keep the lazy conversion into a string, do the conversion of the whole string on the first read and keep the string until the error state is freed. v2: Don't double advance simple_read_from_buffer v3: Due to extreme pain of lack of vrealloc, use a scatterlist v4: Keep the forward iterator loosely cached v5: Stylistic improvements to reduce patch size Reported-by: Jason Ekstrand <jason@jlekstrand.net> Testcase: igt/gem_exec_capture/many* Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Jason Ekstrand <jason@jlekstrand.net> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20181123132325.26541-1-chris@chris-wilson.co.uk
This commit is contained in:
@@ -943,30 +943,30 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
|
||||
static ssize_t gpu_state_read(struct file *file, char __user *ubuf,
|
||||
size_t count, loff_t *pos)
|
||||
{
|
||||
struct i915_gpu_state *error = file->private_data;
|
||||
struct drm_i915_error_state_buf str;
|
||||
struct i915_gpu_state *error;
|
||||
ssize_t ret;
|
||||
loff_t tmp;
|
||||
void *buf;
|
||||
|
||||
error = file->private_data;
|
||||
if (!error)
|
||||
return 0;
|
||||
|
||||
ret = i915_error_state_buf_init(&str, error->i915, count, *pos);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Bounce buffer required because of kernfs __user API convenience. */
|
||||
buf = kmalloc(count, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = i915_error_state_to_str(&str, error);
|
||||
if (ret)
|
||||
ret = i915_gpu_state_copy_to_buffer(error, buf, *pos, count);
|
||||
if (ret <= 0)
|
||||
goto out;
|
||||
|
||||
tmp = 0;
|
||||
ret = simple_read_from_buffer(ubuf, count, &tmp, str.buf, str.bytes);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (!copy_to_user(ubuf, buf, ret))
|
||||
*pos += ret;
|
||||
else
|
||||
ret = -EFAULT;
|
||||
|
||||
*pos = str.start + ret;
|
||||
out:
|
||||
i915_error_state_buf_release(&str);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -192,6 +192,8 @@ struct i915_gpu_state {
|
||||
} *active_bo[I915_NUM_ENGINES], *pinned_bo;
|
||||
u32 active_bo_count[I915_NUM_ENGINES], pinned_bo_count;
|
||||
struct i915_address_space *active_vm[I915_NUM_ENGINES];
|
||||
|
||||
struct scatterlist *sgl, *fit;
|
||||
};
|
||||
|
||||
struct i915_gpu_error {
|
||||
@@ -298,29 +300,20 @@ struct i915_gpu_error {
|
||||
|
||||
struct drm_i915_error_state_buf {
|
||||
struct drm_i915_private *i915;
|
||||
unsigned int bytes;
|
||||
unsigned int size;
|
||||
struct scatterlist *sgl, *cur, *end;
|
||||
|
||||
char *buf;
|
||||
size_t bytes;
|
||||
size_t size;
|
||||
loff_t iter;
|
||||
|
||||
int err;
|
||||
u8 *buf;
|
||||
loff_t start;
|
||||
loff_t pos;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
|
||||
|
||||
__printf(2, 3)
|
||||
void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
|
||||
int i915_error_state_to_str(struct drm_i915_error_state_buf *estr,
|
||||
const struct i915_gpu_state *gpu);
|
||||
int i915_error_state_buf_init(struct drm_i915_error_state_buf *eb,
|
||||
struct drm_i915_private *i915,
|
||||
size_t count, loff_t pos);
|
||||
|
||||
static inline void
|
||||
i915_error_state_buf_release(struct drm_i915_error_state_buf *eb)
|
||||
{
|
||||
kfree(eb->buf);
|
||||
}
|
||||
|
||||
struct i915_gpu_state *i915_capture_gpu_state(struct drm_i915_private *i915);
|
||||
void i915_capture_error_state(struct drm_i915_private *dev_priv,
|
||||
@@ -334,6 +327,9 @@ i915_gpu_state_get(struct i915_gpu_state *gpu)
|
||||
return gpu;
|
||||
}
|
||||
|
||||
ssize_t i915_gpu_state_copy_to_buffer(struct i915_gpu_state *error,
|
||||
char *buf, loff_t offset, size_t count);
|
||||
|
||||
void __i915_gpu_state_free(struct kref *kref);
|
||||
static inline void i915_gpu_state_put(struct i915_gpu_state *gpu)
|
||||
{
|
||||
|
||||
@@ -516,26 +516,21 @@ static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
|
||||
{
|
||||
|
||||
struct device *kdev = kobj_to_dev(kobj);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
struct drm_i915_error_state_buf error_str;
|
||||
struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
|
||||
struct i915_gpu_state *gpu;
|
||||
ssize_t ret;
|
||||
|
||||
ret = i915_error_state_buf_init(&error_str, dev_priv, count, off);
|
||||
if (ret)
|
||||
return ret;
|
||||
gpu = i915_first_error_state(i915);
|
||||
if (gpu) {
|
||||
ret = i915_gpu_state_copy_to_buffer(gpu, buf, off, count);
|
||||
i915_gpu_state_put(gpu);
|
||||
} else {
|
||||
const char *str = "No error state collected\n";
|
||||
size_t len = strlen(str);
|
||||
|
||||
gpu = i915_first_error_state(dev_priv);
|
||||
ret = i915_error_state_to_str(&error_str, gpu);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = count < error_str.bytes ? count : error_str.bytes;
|
||||
memcpy(buf, error_str.buf, ret);
|
||||
|
||||
out:
|
||||
i915_gpu_state_put(gpu);
|
||||
i915_error_state_buf_release(&error_str);
|
||||
ret = min_t(size_t, count, len - off);
|
||||
memcpy(buf, str + off, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user