diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2024-04-04 07:56:51 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2024-04-04 07:56:51 +0000 |
commit | bfdde264ff52a8e2be2ddc082f27a872bf0f6bf0 (patch) | |
tree | b27c322d4cfc1911c065bae462eb764e7560b2c6 /sys | |
parent | 8af13864866651e5eab74d610c0adc9d9f6a4be7 (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.c | 46 |
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 = { |