Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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()

+75 -26
+29 -8
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
··· 358 358 struct queue *q, 359 359 struct qcm_process_device *qpd) 360 360 { 361 - int retval; 362 361 struct mqd_manager *mqd_mgr; 362 + int retval; 363 363 364 364 mqd_mgr = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); 365 365 if (!mqd_mgr) ··· 387 387 if (!q->properties.is_active) 388 388 return 0; 389 389 390 - retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe, q->queue, 391 - &q->properties, q->process->mm); 390 + if (WARN(q->process->mm != current->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 396 if (retval) 393 397 goto out_uninit_mqd; 394 398 ··· 549 545 retval = map_queues_cpsch(dqm); 550 546 else if (q->properties.is_active && 551 547 (q->properties.type == KFD_QUEUE_TYPE_COMPUTE || 552 - q->properties.type == KFD_QUEUE_TYPE_SDMA)) 553 - retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe, q->queue, 554 - &q->properties, q->process->mm); 548 + q->properties.type == KFD_QUEUE_TYPE_SDMA)) { 549 + if (WARN(q->process->mm != current->mm, 550 + "should only run in user thread")) 551 + retval = -EFAULT; 552 + else 553 + retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, 554 + q->pipe, q->queue, 555 + &q->properties, current->mm); 556 + } 555 557 556 558 out_unlock: 557 559 dqm_unlock(dqm); ··· 663 653 static int restore_process_queues_nocpsch(struct device_queue_manager *dqm, 664 654 struct qcm_process_device *qpd) 665 655 { 656 + struct mm_struct *mm = NULL; 666 657 struct queue *q; 667 658 struct mqd_manager *mqd_mgr; 668 659 struct kfd_process_device *pdd; ··· 697 686 kfd_flush_tlb(pdd); 698 687 } 699 688 689 + /* Take a safe reference to the mm_struct, which may otherwise 690 + * disappear even while the kfd_process is still referenced. 691 + */ 692 + mm = get_task_mm(pdd->process->lead_thread); 693 + if (!mm) { 694 + retval = -EFAULT; 695 + goto out; 696 + } 697 + 700 698 /* activate all active queues on the qpd */ 701 699 list_for_each_entry(q, &qpd->queues_list, list) { 702 700 if (!q->properties.is_evicted) ··· 720 700 q->properties.is_evicted = false; 721 701 q->properties.is_active = true; 722 702 retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe, 723 - q->queue, &q->properties, 724 - q->process->mm); 703 + q->queue, &q->properties, mm); 725 704 if (retval) 726 705 goto out; 727 706 dqm->queue_count++; 728 707 } 729 708 qpd->evicted = 0; 730 709 out: 710 + if (mm) 711 + mmput(mm); 731 712 dqm_unlock(dqm); 732 713 return retval; 733 714 }
+8 -2
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 4633 4633 } 4634 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 4637 if (wait_for_vblank) 4640 4638 drm_atomic_helper_wait_for_flip_done(dev, state); 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); 4641 4647 4642 4648 drm_atomic_helper_cleanup_planes(dev, state); 4643 4649
+26 -9
drivers/gpu/drm/drm_client.c
··· 63 63 EXPORT_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 67 * @dev: DRM device 68 68 * @client: DRM client 69 69 * @name: Client name 70 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 73 * The caller needs to hold a reference on @dev before calling this function. 73 74 * The client is freed when the &drm_device is unregistered. See drm_client_release(). 74 75 * 75 76 * Returns: 76 77 * Zero on success or negative error code on failure. 77 78 */ 78 - int drm_client_new(struct drm_device *dev, struct drm_client_dev *client, 79 - const char *name, const struct drm_client_funcs *funcs) 79 + int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, 80 + const char *name, const struct drm_client_funcs *funcs) 80 81 { 81 82 int ret; 82 83 ··· 96 95 if (ret) 97 96 goto err_put_module; 98 97 99 - mutex_lock(&dev->clientlist_mutex); 100 - list_add(&client->list, &dev->clientlist); 101 - mutex_unlock(&dev->clientlist_mutex); 102 - 103 98 drm_dev_get(dev); 104 99 105 100 return 0; ··· 106 109 107 110 return ret; 108 111 } 109 - EXPORT_SYMBOL(drm_client_new); 112 + EXPORT_SYMBOL(drm_client_init); 113 + 114 + /** 115 + * drm_client_add - Add client to the device list 116 + * @client: DRM client 117 + * 118 + * Add the client to the &drm_device client list to activate its callbacks. 119 + * @client must be initialized by a call to drm_client_init(). After 120 + * drm_client_add() it is no longer permissible to call drm_client_release() 121 + * directly (outside the unregister callback), instead cleanup will happen 122 + * automatically on driver unload. 123 + */ 124 + void drm_client_add(struct drm_client_dev *client) 125 + { 126 + struct drm_device *dev = client->dev; 127 + 128 + mutex_lock(&dev->clientlist_mutex); 129 + list_add(&client->list, &dev->clientlist); 130 + mutex_unlock(&dev->clientlist_mutex); 131 + } 132 + EXPORT_SYMBOL(drm_client_add); 110 133 111 134 /** 112 135 * drm_client_release - Release DRM client resources 113 136 * @client: DRM client 114 137 * 115 - * Releases resources by closing the &drm_file that was opened by drm_client_new(). 138 + * Releases resources by closing the &drm_file that was opened by drm_client_init(). 116 139 * It is called automatically if the &drm_client_funcs.unregister callback is _not_ set. 117 140 * 118 141 * This function should only be called from the unregister callback. An exception
+3 -1
drivers/gpu/drm/drm_fb_cma_helper.c
··· 160 160 161 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 164 if (ret) 165 165 goto err_free; 166 166 ··· 168 168 preferred_bpp, max_conn_count); 169 169 if (ret) 170 170 goto err_client_put; 171 + 172 + drm_client_add(&fb_helper->client); 171 173 172 174 return fbdev_cma; 173 175
+3 -1
drivers/gpu/drm/drm_fb_helper.c
··· 3218 3218 if (!fb_helper) 3219 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 3222 if (ret) { 3223 3223 kfree(fb_helper); 3224 3224 return ret; 3225 3225 } 3226 + 3227 + drm_client_add(&fb_helper->client); 3226 3228 3227 3229 fb_helper->preferred_bpp = preferred_bpp; 3228 3230
+3 -3
drivers/gpu/drm/drm_lease.c
··· 566 566 lessee_priv->is_master = 1; 567 567 lessee_priv->authenticated = 1; 568 568 569 - /* Hook up the fd */ 570 - fd_install(fd, lessee_file); 571 - 572 569 /* Pass fd back to userspace */ 573 570 DRM_DEBUG_LEASE("Returning fd %d id %d\n", fd, lessee->lessee_id); 574 571 cl->fd = fd; 575 572 cl->lessee_id = lessee->lessee_id; 573 + 574 + /* Hook up the fd */ 575 + fd_install(fd, lessee_file); 576 576 577 577 DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n"); 578 578 return 0;
+3 -2
include/drm/drm_client.h
··· 87 87 struct drm_file *file; 88 88 }; 89 89 90 - int drm_client_new(struct drm_device *dev, struct drm_client_dev *client, 91 - const char *name, const struct drm_client_funcs *funcs); 90 + int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, 91 + const char *name, const struct drm_client_funcs *funcs); 92 92 void drm_client_release(struct drm_client_dev *client); 93 + void drm_client_add(struct drm_client_dev *client); 93 94 94 95 void drm_client_dev_unregister(struct drm_device *dev); 95 96 void drm_client_dev_hotplug(struct drm_device *dev);