summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2024-04-04 07:56:51 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2024-04-04 07:56:51 +0000
commitbfdde264ff52a8e2be2ddc082f27a872bf0f6bf0 (patch)
treeb27c322d4cfc1911c065bae462eb764e7560b2c6 /sys
parent8af13864866651e5eab74d610c0adc9d9f6a4be7 (diff)
drm/amdgpu: fix deadlock while reading mqd from debugfs
From Johannes Weiner 197f6d6987c55860f6eea1c93e4f800c59078874 in linux-6.6.y/6.6.24 8678b1060ae2b75feb60b87e5b75e17374e3c1c5 in mainline linux
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/drm/amd/amdgpu/amdgpu_ring.c46
1 files changed, 29 insertions, 17 deletions
diff --git a/sys/dev/pci/drm/amd/amdgpu/amdgpu_ring.c b/sys/dev/pci/drm/amd/amdgpu/amdgpu_ring.c
index 80d6e132e40..dbde3b41c08 100644
--- a/sys/dev/pci/drm/amd/amdgpu/amdgpu_ring.c
+++ b/sys/dev/pci/drm/amd/amdgpu/amdgpu_ring.c
@@ -520,46 +520,58 @@ static ssize_t amdgpu_debugfs_mqd_read(struct file *f, char __user *buf,
{
struct amdgpu_ring *ring = file_inode(f)->i_private;
volatile u32 *mqd;
- int r;
+ u32 *kbuf;
+ int r, i;
uint32_t value, result;
if (*pos & 3 || size & 3)
return -EINVAL;
- result = 0;
+ kbuf = kmalloc(ring->mqd_size, GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
r = amdgpu_bo_reserve(ring->mqd_obj, false);
if (unlikely(r != 0))
- return r;
+ goto err_free;
r = amdgpu_bo_kmap(ring->mqd_obj, (void **)&mqd);
- if (r) {
- amdgpu_bo_unreserve(ring->mqd_obj);
- return r;
- }
+ if (r)
+ goto err_unreserve;
+ /*
+ * Copy to local buffer to avoid put_user(), which might fault
+ * and acquire mmap_sem, under reservation_ww_class_mutex.
+ */
+ for (i = 0; i < ring->mqd_size/sizeof(u32); i++)
+ kbuf[i] = mqd[i];
+
+ amdgpu_bo_kunmap(ring->mqd_obj);
+ amdgpu_bo_unreserve(ring->mqd_obj);
+
+ result = 0;
while (size) {
if (*pos >= ring->mqd_size)
- goto done;
+ break;
- value = mqd[*pos/4];
+ value = kbuf[*pos/4];
r = put_user(value, (uint32_t *)buf);
if (r)
- goto done;
+ goto err_free;
buf += 4;
result += 4;
size -= 4;
*pos += 4;
}
-done:
- amdgpu_bo_kunmap(ring->mqd_obj);
- mqd = NULL;
- amdgpu_bo_unreserve(ring->mqd_obj);
- if (r)
- return r;
-
+ kfree(kbuf);
return result;
+
+err_unreserve:
+ amdgpu_bo_unreserve(ring->mqd_obj);
+err_free:
+ kfree(kbuf);
+ return r;
}
static const struct file_operations amdgpu_debugfs_mqd_fops = {