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

Configure Feed

Select the types of activity you want to include in your feed.

drm: Rip out the racy, unused vblank signal code.

Schedule a vblank signal, kill the process, and we'll go walking over freed
memory. Given that no open-source userland exists using this, nor have I
ever heard of a consumer, just let this code die.

Signed-off-by: Eric Anholt <eric@anholt.net>
Requested-by: Linus Torvalds <torvalds@linux-foundation.org>
Acked-by: Dave Airlie <airlied@linux.ie>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Eric Anholt and committed by
Linus Torvalds
30b23634 152a649b

+24 -148
+23 -138
drivers/gpu/drm/drm_irq.c
··· 106 106 107 107 drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, 108 108 DRM_MEM_DRIVER); 109 - drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, 110 - DRM_MEM_DRIVER); 111 109 drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * 112 110 dev->num_crtcs, DRM_MEM_DRIVER); 113 111 drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * ··· 130 132 setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, 131 133 (unsigned long)dev); 132 134 spin_lock_init(&dev->vbl_lock); 133 - atomic_set(&dev->vbl_signal_pending, 0); 134 135 dev->num_crtcs = num_crtcs; 135 136 136 137 dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, 137 138 DRM_MEM_DRIVER); 138 139 if (!dev->vbl_queue) 139 - goto err; 140 - 141 - dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs, 142 - DRM_MEM_DRIVER); 143 - if (!dev->vbl_sigs) 144 140 goto err; 145 141 146 142 dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, ··· 169 177 /* Zero per-crtc vblank stuff */ 170 178 for (i = 0; i < num_crtcs; i++) { 171 179 init_waitqueue_head(&dev->vbl_queue[i]); 172 - INIT_LIST_HEAD(&dev->vbl_sigs[i]); 173 180 atomic_set(&dev->_vblank_count[i], 0); 174 181 atomic_set(&dev->vblank_refcount[i], 0); 175 182 } ··· 531 540 * \param data user argument, pointing to a drm_wait_vblank structure. 532 541 * \return zero on success or a negative number on failure. 533 542 * 534 - * Verifies the IRQ is installed. 535 - * 536 - * If a signal is requested checks if this task has already scheduled the same signal 537 - * for the same vblank sequence number - nothing to be done in 538 - * that case. If the number of tasks waiting for the interrupt exceeds 100 the 539 - * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this 540 - * task. 541 - * 542 - * If a signal is not requested, then calls vblank_wait(). 543 + * This function enables the vblank interrupt on the pipe requested, then 544 + * sleeps waiting for the requested sequence number to occur, and drops 545 + * the vblank interrupt refcount afterwards. (vblank irq disable follows that 546 + * after a timeout with no further vblank waits scheduled). 543 547 */ 544 548 int drm_wait_vblank(struct drm_device *dev, void *data, 545 549 struct drm_file *file_priv) ··· 544 558 unsigned int flags, seq, crtc; 545 559 546 560 if ((!dev->pdev->irq) || (!dev->irq_enabled)) 561 + return -EINVAL; 562 + 563 + if (vblwait->request.type & _DRM_VBLANK_SIGNAL) 547 564 return -EINVAL; 548 565 549 566 if (vblwait->request.type & ··· 586 597 vblwait->request.sequence = seq + 1; 587 598 } 588 599 589 - if (flags & _DRM_VBLANK_SIGNAL) { 590 - unsigned long irqflags; 591 - struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; 592 - struct drm_vbl_sig *vbl_sig; 600 + DRM_DEBUG("waiting on vblank count %d, crtc %d\n", 601 + vblwait->request.sequence, crtc); 602 + dev->last_vblank_wait[crtc] = vblwait->request.sequence; 603 + DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, 604 + (((drm_vblank_count(dev, crtc) - 605 + vblwait->request.sequence) <= (1 << 23)) || 606 + !dev->irq_enabled)); 593 607 594 - spin_lock_irqsave(&dev->vbl_lock, irqflags); 608 + if (ret != -EINTR) { 609 + struct timeval now; 595 610 596 - /* Check if this task has already scheduled the same signal 597 - * for the same vblank sequence number; nothing to be done in 598 - * that case 599 - */ 600 - list_for_each_entry(vbl_sig, vbl_sigs, head) { 601 - if (vbl_sig->sequence == vblwait->request.sequence 602 - && vbl_sig->info.si_signo == 603 - vblwait->request.signal 604 - && vbl_sig->task == current) { 605 - spin_unlock_irqrestore(&dev->vbl_lock, 606 - irqflags); 607 - vblwait->reply.sequence = seq; 608 - goto done; 609 - } 610 - } 611 + do_gettimeofday(&now); 611 612 612 - if (atomic_read(&dev->vbl_signal_pending) >= 100) { 613 - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 614 - ret = -EBUSY; 615 - goto done; 616 - } 617 - 618 - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 619 - 620 - vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig), 621 - DRM_MEM_DRIVER); 622 - if (!vbl_sig) { 623 - ret = -ENOMEM; 624 - goto done; 625 - } 626 - 627 - /* Get a refcount on the vblank, which will be released by 628 - * drm_vbl_send_signals(). 629 - */ 630 - ret = drm_vblank_get(dev, crtc); 631 - if (ret) { 632 - drm_free(vbl_sig, sizeof(struct drm_vbl_sig), 633 - DRM_MEM_DRIVER); 634 - goto done; 635 - } 636 - 637 - atomic_inc(&dev->vbl_signal_pending); 638 - 639 - vbl_sig->sequence = vblwait->request.sequence; 640 - vbl_sig->info.si_signo = vblwait->request.signal; 641 - vbl_sig->task = current; 642 - 643 - spin_lock_irqsave(&dev->vbl_lock, irqflags); 644 - 645 - list_add_tail(&vbl_sig->head, vbl_sigs); 646 - 647 - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 648 - 649 - vblwait->reply.sequence = seq; 613 + vblwait->reply.tval_sec = now.tv_sec; 614 + vblwait->reply.tval_usec = now.tv_usec; 615 + vblwait->reply.sequence = drm_vblank_count(dev, crtc); 616 + DRM_DEBUG("returning %d to client\n", 617 + vblwait->reply.sequence); 650 618 } else { 651 - DRM_DEBUG("waiting on vblank count %d, crtc %d\n", 652 - vblwait->request.sequence, crtc); 653 - dev->last_vblank_wait[crtc] = vblwait->request.sequence; 654 - DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, 655 - (((drm_vblank_count(dev, crtc) - 656 - vblwait->request.sequence) <= (1 << 23)) || 657 - !dev->irq_enabled)); 658 - 659 - if (ret != -EINTR) { 660 - struct timeval now; 661 - 662 - do_gettimeofday(&now); 663 - 664 - vblwait->reply.tval_sec = now.tv_sec; 665 - vblwait->reply.tval_usec = now.tv_usec; 666 - vblwait->reply.sequence = drm_vblank_count(dev, crtc); 667 - DRM_DEBUG("returning %d to client\n", 668 - vblwait->reply.sequence); 669 - } else { 670 - DRM_DEBUG("vblank wait interrupted by signal\n"); 671 - } 619 + DRM_DEBUG("vblank wait interrupted by signal\n"); 672 620 } 673 621 674 622 done: 675 623 drm_vblank_put(dev, crtc); 676 624 return ret; 677 - } 678 - 679 - /** 680 - * Send the VBLANK signals. 681 - * 682 - * \param dev DRM device. 683 - * \param crtc CRTC where the vblank event occurred 684 - * 685 - * Sends a signal for each task in drm_device::vbl_sigs and empties the list. 686 - * 687 - * If a signal is not requested, then calls vblank_wait(). 688 - */ 689 - static void drm_vbl_send_signals(struct drm_device *dev, int crtc) 690 - { 691 - struct drm_vbl_sig *vbl_sig, *tmp; 692 - struct list_head *vbl_sigs; 693 - unsigned int vbl_seq; 694 - unsigned long flags; 695 - 696 - spin_lock_irqsave(&dev->vbl_lock, flags); 697 - 698 - vbl_sigs = &dev->vbl_sigs[crtc]; 699 - vbl_seq = drm_vblank_count(dev, crtc); 700 - 701 - list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { 702 - if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { 703 - vbl_sig->info.si_code = vbl_seq; 704 - send_sig_info(vbl_sig->info.si_signo, 705 - &vbl_sig->info, vbl_sig->task); 706 - 707 - list_del(&vbl_sig->head); 708 - 709 - drm_free(vbl_sig, sizeof(*vbl_sig), 710 - DRM_MEM_DRIVER); 711 - atomic_dec(&dev->vbl_signal_pending); 712 - drm_vblank_put(dev, crtc); 713 - } 714 - } 715 - 716 - spin_unlock_irqrestore(&dev->vbl_lock, flags); 717 625 } 718 626 719 627 /** ··· 625 739 { 626 740 atomic_inc(&dev->_vblank_count[crtc]); 627 741 DRM_WAKEUP(&dev->vbl_queue[crtc]); 628 - drm_vbl_send_signals(dev, crtc); 629 742 } 630 743 EXPORT_SYMBOL(drm_handle_vblank);
+1 -1
include/drm/drm.h
··· 458 458 _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ 459 459 _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ 460 460 _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ 461 - _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ 461 + _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking, unsupported */ 462 462 }; 463 463 464 464 #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
-9
include/drm/drmP.h
··· 545 545 struct drm_file *tag; /**< associated fd private data */ 546 546 }; 547 547 548 - struct drm_vbl_sig { 549 - struct list_head head; 550 - unsigned int sequence; 551 - struct siginfo info; 552 - struct task_struct *task; 553 - }; 554 - 555 548 /* location of GART table */ 556 549 #define DRM_ATI_GART_MAIN 1 557 550 #define DRM_ATI_GART_FB 2 ··· 896 903 wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ 897 904 atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ 898 905 spinlock_t vbl_lock; 899 - struct list_head *vbl_sigs; /**< signal list to send on VBLANK */ 900 - atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/ 901 906 atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */ 902 907 u32 *last_vblank; /* protected by dev->vbl_lock, used */ 903 908 /* for wraparound handling */