aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-10-04 20:23:58 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-10-04 20:23:58 -0400
commitbefad944e2312c18d855013ce154ca7d2b110ade (patch)
tree544f38cb6d0a2a35794a33cf9e37396787e7bea1
parent010bd965f9711f801f2902ec3a6a2826c6656491 (diff)
parentbdf800c6fdf5674999bc0228d5040cc0ae218fa8 (diff)
Merge tag 'drm-fixes-2018-10-05' of git://anongit.freedesktop.org/drm/drm
Dave writes: "amdgpu and two core fixes Two fixes for amdgpu: one corrects a use of process->mm one fix for display code race condition that can result in a crash Two core fixes: One for a use-after-free in the leasing code One for a cma/fbdev crash." * tag 'drm-fixes-2018-10-05' of git://anongit.freedesktop.org/drm/drm: drm/amdkfd: Fix incorrect use of process->mm drm/amd/display: Signal hw_done() after waiting for flip_done() drm/cma-helper: Fix crash in fbdev error path drm: fix use-after-free read in drm_mode_create_lease_ioctl()
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c37
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c10
-rw-r--r--drivers/gpu/drm/drm_client.c35
-rw-r--r--drivers/gpu/drm/drm_fb_cma_helper.c4
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c4
-rw-r--r--drivers/gpu/drm/drm_lease.c6
-rw-r--r--include/drm/drm_client.h5
7 files changed, 75 insertions, 26 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index ec0d62a16e53..4f22e745df51 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -358,8 +358,8 @@ static int create_compute_queue_nocpsch(struct device_queue_manager *dqm,
358 struct queue *q, 358 struct queue *q,
359 struct qcm_process_device *qpd) 359 struct qcm_process_device *qpd)
360{ 360{
361 int retval;
362 struct mqd_manager *mqd_mgr; 361 struct mqd_manager *mqd_mgr;
362 int retval;
363 363
364 mqd_mgr = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); 364 mqd_mgr = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE);
365 if (!mqd_mgr) 365 if (!mqd_mgr)
@@ -387,8 +387,12 @@ static int create_compute_queue_nocpsch(struct device_queue_manager *dqm,
387 if (!q->properties.is_active) 387 if (!q->properties.is_active)
388 return 0; 388 return 0;
389 389
390 retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe, q->queue, 390 if (WARN(q->process->mm != current->mm,
391 &q->properties, q->process->mm); 391 "should only run in user thread"))
392 retval = -EFAULT;
393 else
394 retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe, q->queue,
395 &q->properties, current->mm);
392 if (retval) 396 if (retval)
393 goto out_uninit_mqd; 397 goto out_uninit_mqd;
394 398
@@ -545,9 +549,15 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q)
545 retval = map_queues_cpsch(dqm); 549 retval = map_queues_cpsch(dqm);
546 else if (q->properties.is_active && 550 else if (q->properties.is_active &&
547 (q->properties.type == KFD_QUEUE_TYPE_COMPUTE || 551 (q->properties.type == KFD_QUEUE_TYPE_COMPUTE ||
548 q->properties.type == KFD_QUEUE_TYPE_SDMA)) 552 q->properties.type == KFD_QUEUE_TYPE_SDMA)) {
549 retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe, q->queue, 553 if (WARN(q->process->mm != current->mm,
550 &q->properties, q->process->mm); 554 "should only run in user thread"))
555 retval = -EFAULT;
556 else
557 retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd,
558 q->pipe, q->queue,
559 &q->properties, current->mm);
560 }
551 561
552out_unlock: 562out_unlock:
553 dqm_unlock(dqm); 563 dqm_unlock(dqm);
@@ -653,6 +663,7 @@ out:
653static int restore_process_queues_nocpsch(struct device_queue_manager *dqm, 663static int restore_process_queues_nocpsch(struct device_queue_manager *dqm,
654 struct qcm_process_device *qpd) 664 struct qcm_process_device *qpd)
655{ 665{
666 struct mm_struct *mm = NULL;
656 struct queue *q; 667 struct queue *q;
657 struct mqd_manager *mqd_mgr; 668 struct mqd_manager *mqd_mgr;
658 struct kfd_process_device *pdd; 669 struct kfd_process_device *pdd;
@@ -686,6 +697,15 @@ static int restore_process_queues_nocpsch(struct device_queue_manager *dqm,
686 kfd_flush_tlb(pdd); 697 kfd_flush_tlb(pdd);
687 } 698 }
688 699
700 /* Take a safe reference to the mm_struct, which may otherwise
701 * disappear even while the kfd_process is still referenced.
702 */
703 mm = get_task_mm(pdd->process->lead_thread);
704 if (!mm) {
705 retval = -EFAULT;
706 goto out;
707 }
708
689 /* activate all active queues on the qpd */ 709 /* activate all active queues on the qpd */
690 list_for_each_entry(q, &qpd->queues_list, list) { 710 list_for_each_entry(q, &qpd->queues_list, list) {
691 if (!q->properties.is_evicted) 711 if (!q->properties.is_evicted)
@@ -700,14 +720,15 @@ static int restore_process_queues_nocpsch(struct device_queue_manager *dqm,
700 q->properties.is_evicted = false; 720 q->properties.is_evicted = false;
701 q->properties.is_active = true; 721 q->properties.is_active = true;
702 retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe, 722 retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe,
703 q->queue, &q->properties, 723 q->queue, &q->properties, mm);
704 q->process->mm);
705 if (retval) 724 if (retval)
706 goto out; 725 goto out;
707 dqm->queue_count++; 726 dqm->queue_count++;
708 } 727 }
709 qpd->evicted = 0; 728 qpd->evicted = 0;
710out: 729out:
730 if (mm)
731 mmput(mm);
711 dqm_unlock(dqm); 732 dqm_unlock(dqm);
712 return retval; 733 return retval;
713} 734}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 96875950845a..6903fe6c894b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4633,12 +4633,18 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
4633 } 4633 }
4634 spin_unlock_irqrestore(&adev->ddev->event_lock, flags); 4634 spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
4635 4635
4636 /* Signal HW programming completion */
4637 drm_atomic_helper_commit_hw_done(state);
4638 4636
4639 if (wait_for_vblank) 4637 if (wait_for_vblank)
4640 drm_atomic_helper_wait_for_flip_done(dev, state); 4638 drm_atomic_helper_wait_for_flip_done(dev, state);
4641 4639
4640 /*
4641 * FIXME:
4642 * Delay hw_done() until flip_done() is signaled. This is to block
4643 * another commit from freeing the CRTC state while we're still
4644 * waiting on flip_done.
4645 */
4646 drm_atomic_helper_commit_hw_done(state);
4647
4642 drm_atomic_helper_cleanup_planes(dev, state); 4648 drm_atomic_helper_cleanup_planes(dev, state);
4643 4649
4644 /* Finally, drop a runtime PM reference for each newly disabled CRTC, 4650 /* Finally, drop a runtime PM reference for each newly disabled CRTC,
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index baff50a4c234..df31c3815092 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -63,20 +63,21 @@ static void drm_client_close(struct drm_client_dev *client)
63EXPORT_SYMBOL(drm_client_close); 63EXPORT_SYMBOL(drm_client_close);
64 64
65/** 65/**
66 * drm_client_new - Create a DRM client 66 * drm_client_init - Initialise a DRM client
67 * @dev: DRM device 67 * @dev: DRM device
68 * @client: DRM client 68 * @client: DRM client
69 * @name: Client name 69 * @name: Client name
70 * @funcs: DRM client functions (optional) 70 * @funcs: DRM client functions (optional)
71 * 71 *
72 * This initialises the client and opens a &drm_file. Use drm_client_add() to complete the process.
72 * The caller needs to hold a reference on @dev before calling this function. 73 * The caller needs to hold a reference on @dev before calling this function.
73 * The client is freed when the &drm_device is unregistered. See drm_client_release(). 74 * The client is freed when the &drm_device is unregistered. See drm_client_release().
74 * 75 *
75 * Returns: 76 * Returns:
76 * Zero on success or negative error code on failure. 77 * Zero on success or negative error code on failure.
77 */ 78 */
78int drm_client_new(struct drm_device *dev, struct drm_client_dev *client, 79int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
79 const char *name, const struct drm_client_funcs *funcs) 80 const char *name, const struct drm_client_funcs *funcs)
80{ 81{
81 int ret; 82 int ret;
82 83
@@ -95,10 +96,6 @@ int drm_client_new(struct drm_device *dev, struct drm_client_dev *client,
95 if (ret) 96 if (ret)
96 goto err_put_module; 97 goto err_put_module;
97 98
98 mutex_lock(&dev->clientlist_mutex);
99 list_add(&client->list, &dev->clientlist);
100 mutex_unlock(&dev->clientlist_mutex);
101
102 drm_dev_get(dev); 99 drm_dev_get(dev);
103 100
104 return 0; 101 return 0;
@@ -109,13 +106,33 @@ err_put_module:
109 106
110 return ret; 107 return ret;
111} 108}
112EXPORT_SYMBOL(drm_client_new); 109EXPORT_SYMBOL(drm_client_init);
110
111/**
112 * drm_client_add - Add client to the device list
113 * @client: DRM client
114 *
115 * Add the client to the &drm_device client list to activate its callbacks.
116 * @client must be initialized by a call to drm_client_init(). After
117 * drm_client_add() it is no longer permissible to call drm_client_release()
118 * directly (outside the unregister callback), instead cleanup will happen
119 * automatically on driver unload.
120 */
121void drm_client_add(struct drm_client_dev *client)
122{
123 struct drm_device *dev = client->dev;
124
125 mutex_lock(&dev->clientlist_mutex);
126 list_add(&client->list, &dev->clientlist);
127 mutex_unlock(&dev->clientlist_mutex);
128}
129EXPORT_SYMBOL(drm_client_add);
113 130
114/** 131/**
115 * drm_client_release - Release DRM client resources 132 * drm_client_release - Release DRM client resources
116 * @client: DRM client 133 * @client: DRM client
117 * 134 *
118 * Releases resources by closing the &drm_file that was opened by drm_client_new(). 135 * Releases resources by closing the &drm_file that was opened by drm_client_init().
119 * It is called automatically if the &drm_client_funcs.unregister callback is _not_ set. 136 * It is called automatically if the &drm_client_funcs.unregister callback is _not_ set.
120 * 137 *
121 * This function should only be called from the unregister callback. An exception 138 * This function should only be called from the unregister callback. An exception
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index 9da36a6271d3..9ac1f2e0f064 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -160,7 +160,7 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
160 160
161 fb_helper = &fbdev_cma->fb_helper; 161 fb_helper = &fbdev_cma->fb_helper;
162 162
163 ret = drm_client_new(dev, &fb_helper->client, "fbdev", NULL); 163 ret = drm_client_init(dev, &fb_helper->client, "fbdev", NULL);
164 if (ret) 164 if (ret)
165 goto err_free; 165 goto err_free;
166 166
@@ -169,6 +169,8 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
169 if (ret) 169 if (ret)
170 goto err_client_put; 170 goto err_client_put;
171 171
172 drm_client_add(&fb_helper->client);
173
172 return fbdev_cma; 174 return fbdev_cma;
173 175
174err_client_put: 176err_client_put:
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 16ec93b75dbf..515a7aec57ac 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -3218,12 +3218,14 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
3218 if (!fb_helper) 3218 if (!fb_helper)
3219 return -ENOMEM; 3219 return -ENOMEM;
3220 3220
3221 ret = drm_client_new(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs); 3221 ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
3222 if (ret) { 3222 if (ret) {
3223 kfree(fb_helper); 3223 kfree(fb_helper);
3224 return ret; 3224 return ret;
3225 } 3225 }
3226 3226
3227 drm_client_add(&fb_helper->client);
3228
3227 fb_helper->preferred_bpp = preferred_bpp; 3229 fb_helper->preferred_bpp = preferred_bpp;
3228 3230
3229 drm_fbdev_client_hotplug(&fb_helper->client); 3231 drm_fbdev_client_hotplug(&fb_helper->client);
diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c
index b54fb78a283c..b82da96ded5c 100644
--- a/drivers/gpu/drm/drm_lease.c
+++ b/drivers/gpu/drm/drm_lease.c
@@ -566,14 +566,14 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
566 lessee_priv->is_master = 1; 566 lessee_priv->is_master = 1;
567 lessee_priv->authenticated = 1; 567 lessee_priv->authenticated = 1;
568 568
569 /* Hook up the fd */
570 fd_install(fd, lessee_file);
571
572 /* Pass fd back to userspace */ 569 /* Pass fd back to userspace */
573 DRM_DEBUG_LEASE("Returning fd %d id %d\n", fd, lessee->lessee_id); 570 DRM_DEBUG_LEASE("Returning fd %d id %d\n", fd, lessee->lessee_id);
574 cl->fd = fd; 571 cl->fd = fd;
575 cl->lessee_id = lessee->lessee_id; 572 cl->lessee_id = lessee->lessee_id;
576 573
574 /* Hook up the fd */
575 fd_install(fd, lessee_file);
576
577 DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n"); 577 DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n");
578 return 0; 578 return 0;
579 579
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 989f8e52864d..971bb7853776 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -87,9 +87,10 @@ struct drm_client_dev {
87 struct drm_file *file; 87 struct drm_file *file;
88}; 88};
89 89
90int drm_client_new(struct drm_device *dev, struct drm_client_dev *client, 90int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
91 const char *name, const struct drm_client_funcs *funcs); 91 const char *name, const struct drm_client_funcs *funcs);
92void drm_client_release(struct drm_client_dev *client); 92void drm_client_release(struct drm_client_dev *client);
93void drm_client_add(struct drm_client_dev *client);
93 94
94void drm_client_dev_unregister(struct drm_device *dev); 95void drm_client_dev_unregister(struct drm_device *dev);
95void drm_client_dev_hotplug(struct drm_device *dev); 96void drm_client_dev_hotplug(struct drm_device *dev);