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

udlfb: introduce a rendering mutex

Rendering calls may be done simultaneously from the workqueue,
dlfb_ops_write, dlfb_ops_ioctl, dlfb_ops_set_par and dlfb_dpy_deferred_io.
The code is robust enough so that it won't crash on concurrent rendering.

However, concurrent rendering may cause display corruption if the same
pixel is simultaneously being rendered. In order to avoid this corruption,
this patch adds a mutex around the rendering calls.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Cc: Bernie Thompson <bernie@plugable.com>
Cc: Ladislav Michl <ladis@linux-mips.org>
Cc: <stable@vger.kernel.org>
[b.zolnierkie: replace "dlfb:" with "uldfb:" in the patch summary]
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>

authored by

Mikulas Patocka and committed by
Bartlomiej Zolnierkiewicz
babc250e 6b11f9d8

+31 -11
+30 -11
drivers/video/fbdev/udlfb.c
··· 596 596 597 597 static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, int width, int height) 598 598 { 599 - int i; 599 + int i, ret; 600 600 char *cmd; 601 601 cycles_t start_cycles, end_cycles; 602 602 int bytes_sent = 0; ··· 606 606 607 607 start_cycles = get_cycles(); 608 608 609 + mutex_lock(&dlfb->render_mutex); 610 + 609 611 aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long)); 610 612 width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long)); 611 613 x = aligned_x; 612 614 613 615 if ((width <= 0) || 614 616 (x + width > dlfb->info->var.xres) || 615 - (y + height > dlfb->info->var.yres)) 616 - return -EINVAL; 617 + (y + height > dlfb->info->var.yres)) { 618 + ret = -EINVAL; 619 + goto unlock_ret; 620 + } 617 621 618 - if (!atomic_read(&dlfb->usb_active)) 619 - return 0; 622 + if (!atomic_read(&dlfb->usb_active)) { 623 + ret = 0; 624 + goto unlock_ret; 625 + } 620 626 621 627 urb = dlfb_get_urb(dlfb); 622 - if (!urb) 623 - return 0; 628 + if (!urb) { 629 + ret = 0; 630 + goto unlock_ret; 631 + } 624 632 cmd = urb->transfer_buffer; 625 633 626 634 for (i = y; i < y + height ; i++) { ··· 662 654 >> 10)), /* Kcycles */ 663 655 &dlfb->cpu_kcycles_used); 664 656 665 - return 0; 657 + ret = 0; 658 + 659 + unlock_ret: 660 + mutex_unlock(&dlfb->render_mutex); 661 + return ret; 666 662 } 667 663 668 664 static void dlfb_init_damage(struct dlfb_data *dlfb) ··· 794 782 int bytes_identical = 0; 795 783 int bytes_rendered = 0; 796 784 785 + mutex_lock(&dlfb->render_mutex); 786 + 797 787 if (!fb_defio) 798 - return; 788 + goto unlock_ret; 799 789 800 790 if (!atomic_read(&dlfb->usb_active)) 801 - return; 791 + goto unlock_ret; 802 792 803 793 start_cycles = get_cycles(); 804 794 805 795 urb = dlfb_get_urb(dlfb); 806 796 if (!urb) 807 - return; 797 + goto unlock_ret; 808 798 809 799 cmd = urb->transfer_buffer; 810 800 ··· 839 825 atomic_add(((unsigned int) ((end_cycles - start_cycles) 840 826 >> 10)), /* Kcycles */ 841 827 &dlfb->cpu_kcycles_used); 828 + unlock_ret: 829 + mutex_unlock(&dlfb->render_mutex); 842 830 } 843 831 844 832 static int dlfb_get_edid(struct dlfb_data *dlfb, char *edid, int len) ··· 1001 985 struct dlfb_data *dlfb = info->par; 1002 986 1003 987 cancel_work_sync(&dlfb->damage_work); 988 + 989 + mutex_destroy(&dlfb->render_mutex); 1004 990 1005 991 if (info->cmap.len != 0) 1006 992 fb_dealloc_cmap(&info->cmap); ··· 1700 1682 dlfb->ops = dlfb_ops; 1701 1683 info->fbops = &dlfb->ops; 1702 1684 1685 + mutex_init(&dlfb->render_mutex); 1703 1686 dlfb_init_damage(dlfb); 1704 1687 spin_lock_init(&dlfb->damage_lock); 1705 1688 INIT_WORK(&dlfb->damage_work, dlfb_damage_work);
+1
include/video/udlfb.h
··· 48 48 int base8; 49 49 u32 pseudo_palette[256]; 50 50 int blank_mode; /*one of FB_BLANK_ */ 51 + struct mutex render_mutex; 51 52 int damage_x; 52 53 int damage_y; 53 54 int damage_x2;