From 35178ff3f3ab2620c5f1b62aad96d6320c8e10fe Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 28 Apr 2014 16:10:55 +0000 Subject: [PATCH] Staging: speakup: Move pasting into a work item and update it to match vt (Closes: #735202, #744015) svn path=/dists/trunk/linux/; revision=21276 --- debian/changelog | 2 + ...peakup-Move-pasting-into-a-work-item.patch | 114 ++++++++++++++++++ ...Update-__speakup_paste_selection-tty.patch | 82 +++++++++++++ debian/patches/series | 2 + 4 files changed, 200 insertions(+) create mode 100644 debian/patches/bugfix/all/0001-Staging-speakup-Move-pasting-into-a-work-item.patch create mode 100644 debian/patches/bugfix/all/0002-Staging-speakup-Update-__speakup_paste_selection-tty.patch diff --git a/debian/changelog b/debian/changelog index f47cc2e4e..744fa4209 100644 --- a/debian/changelog +++ b/debian/changelog @@ -19,6 +19,8 @@ linux (3.14.2-1~exp1) UNRELEASED; urgency=medium - Enable PHY_SUN4I_USB, RTC_DRV_SUNXI, SPI_SUN6I, USB_EHCI_HCD_PLATFORM, USB_OHCI_HCD_PLATFORM and CONFIG_SUNXI_WATCHDOG as modules * Set ABI to 1 + * Staging: speakup: Move pasting into a work item and update it to match vt + (Closes: #735202, #744015) -- Ben Hutchings Sun, 20 Apr 2014 21:54:54 +0100 diff --git a/debian/patches/bugfix/all/0001-Staging-speakup-Move-pasting-into-a-work-item.patch b/debian/patches/bugfix/all/0001-Staging-speakup-Move-pasting-into-a-work-item.patch new file mode 100644 index 000000000..4316b503b --- /dev/null +++ b/debian/patches/bugfix/all/0001-Staging-speakup-Move-pasting-into-a-work-item.patch @@ -0,0 +1,114 @@ +From: Ben Hutchings +Date: Sat, 15 Mar 2014 22:34:09 +0000 +Subject: [PATCH 1/2] Staging: speakup: Move pasting into a work item +Bug-Debian: https://bugs.debian.org/735202 +Bug-Debian: https://bugs.debian.org/744015 + +Input is handled in softirq context, but when pasting we may +need to sleep. speakup_paste_selection() currently tries to +bodge this by busy-waiting if in_atomic(), but that doesn't +help because the ldisc may also sleep. + +For bonus breakage, speakup_paste_selection() changes the +state of current, even though it's not running in process +context. + +Move it into a work item and make sure to cancel it on exit. + +Signed-off-by: Ben Hutchings +--- + drivers/staging/speakup/main.c | 1 + + drivers/staging/speakup/selection.c | 38 +++++++++++++++++++++++++++++++------ + drivers/staging/speakup/speakup.h | 1 + + 3 files changed, 34 insertions(+), 6 deletions(-) + +--- a/drivers/staging/speakup/main.c ++++ b/drivers/staging/speakup/main.c +@@ -2218,6 +2218,7 @@ static void __exit speakup_exit(void) + unregister_keyboard_notifier(&keyboard_notifier_block); + unregister_vt_notifier(&vt_notifier_block); + speakup_unregister_devsynth(); ++ speakup_cancel_paste(); + del_timer(&cursor_timer); + kthread_stop(speakup_task); + speakup_task = NULL; +--- a/drivers/staging/speakup/selection.c ++++ b/drivers/staging/speakup/selection.c +@@ -4,6 +4,8 @@ + #include + #include /* for dev_warn */ + #include ++#include ++#include + + #include "speakup.h" + +@@ -121,20 +123,24 @@ int speakup_set_selection(struct tty_str + return 0; + } + +-/* TODO: move to some helper thread, probably. That'd fix having to check for +- * in_atomic(). */ +-int speakup_paste_selection(struct tty_struct *tty) +-{ ++struct speakup_paste_work { ++ struct work_struct work; ++ struct tty_struct *tty; ++}; ++ ++static void __speakup_paste_selection(struct work_struct *work) ++{ ++ struct speakup_paste_work *spw = ++ container_of(work, struct speakup_paste_work, work); ++ struct tty_struct *tty = xchg(&spw->tty, NULL); + struct vc_data *vc = (struct vc_data *) tty->driver_data; + int pasted = 0, count; + DECLARE_WAITQUEUE(wait, current); ++ + add_wait_queue(&vc->paste_wait, &wait); + while (sel_buffer && sel_buffer_lth > pasted) { + set_current_state(TASK_INTERRUPTIBLE); + if (test_bit(TTY_THROTTLED, &tty->flags)) { +- if (in_atomic()) +- /* if we are in an interrupt handler, abort */ +- break; + schedule(); + continue; + } +@@ -146,6 +152,26 @@ int speakup_paste_selection(struct tty_s + } + remove_wait_queue(&vc->paste_wait, &wait); + current->state = TASK_RUNNING; ++ tty_kref_put(tty); ++} ++ ++static struct speakup_paste_work speakup_paste_work = { ++ .work = __WORK_INITIALIZER(speakup_paste_work.work, ++ __speakup_paste_selection) ++}; ++ ++int speakup_paste_selection(struct tty_struct *tty) ++{ ++ if (cmpxchg(&speakup_paste_work.tty, NULL, tty) != NULL) ++ return -EBUSY; ++ ++ tty_kref_get(tty); ++ schedule_work_on(WORK_CPU_UNBOUND, &speakup_paste_work.work); + return 0; + } + ++void speakup_cancel_paste(void) ++{ ++ cancel_work_sync(&speakup_paste_work.work); ++ tty_kref_put(speakup_paste_work.tty); ++} +--- a/drivers/staging/speakup/speakup.h ++++ b/drivers/staging/speakup/speakup.h +@@ -77,6 +77,7 @@ extern void synth_buffer_clear(void); + extern void speakup_clear_selection(void); + extern int speakup_set_selection(struct tty_struct *tty); + extern int speakup_paste_selection(struct tty_struct *tty); ++extern void speakup_cancel_paste(void); + extern void speakup_register_devsynth(void); + extern void speakup_unregister_devsynth(void); + extern void synth_write(const char *buf, size_t count); diff --git a/debian/patches/bugfix/all/0002-Staging-speakup-Update-__speakup_paste_selection-tty.patch b/debian/patches/bugfix/all/0002-Staging-speakup-Update-__speakup_paste_selection-tty.patch new file mode 100644 index 000000000..026c1b48e --- /dev/null +++ b/debian/patches/bugfix/all/0002-Staging-speakup-Update-__speakup_paste_selection-tty.patch @@ -0,0 +1,82 @@ +From: Ben Hutchings +Date: Sat, 15 Mar 2014 22:42:27 +0000 +Subject: [PATCH 2/2] Staging: speakup: Update __speakup_paste_selection() tty + (ab)usage to match vt +Bug-Debian: https://bugs.debian.org/735202 +Bug-Debian: https://bugs.debian.org/744015 + +This function is largely a duplicate of paste_selection() in +drivers/tty/vt/selection.c, but with its own selection state. The +speakup selection mechanism should really be merged with vt. + +For now, apply the changes from 'TTY: vt, fix paste_selection ldisc +handling', 'tty: Make ldisc input flow control concurrency-friendly', +and 'tty: Fix unsafe vt paste_selection()'. + +Signed-off-by: Ben Hutchings +--- + drivers/staging/speakup/selection.c | 14 +++++++++++--- + drivers/tty/tty_buffer.c | 2 ++ + 2 files changed, 13 insertions(+), 3 deletions(-) + +--- a/drivers/staging/speakup/selection.c ++++ b/drivers/staging/speakup/selection.c +@@ -5,6 +5,8 @@ + #include /* for dev_warn */ + #include + #include ++#include ++#include + #include + + #include "speakup.h" +@@ -135,8 +137,12 @@ static void __speakup_paste_selection(st + struct tty_struct *tty = xchg(&spw->tty, NULL); + struct vc_data *vc = (struct vc_data *) tty->driver_data; + int pasted = 0, count; ++ struct tty_ldisc *ld; + DECLARE_WAITQUEUE(wait, current); + ++ ld = tty_ldisc_ref_wait(tty); ++ tty_buffer_lock_exclusive(&vc->port); ++ + add_wait_queue(&vc->paste_wait, &wait); + while (sel_buffer && sel_buffer_lth > pasted) { + set_current_state(TASK_INTERRUPTIBLE); +@@ -145,13 +151,15 @@ static void __speakup_paste_selection(st + continue; + } + count = sel_buffer_lth - pasted; +- count = min_t(int, count, tty->receive_room); +- tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted, +- NULL, count); ++ count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL, ++ count); + pasted += count; + } + remove_wait_queue(&vc->paste_wait, &wait); + current->state = TASK_RUNNING; ++ ++ tty_buffer_unlock_exclusive(&vc->port); ++ tty_ldisc_deref(ld); + tty_kref_put(tty); + } + +--- a/drivers/tty/tty_buffer.c ++++ b/drivers/tty/tty_buffer.c +@@ -60,6 +60,7 @@ void tty_buffer_lock_exclusive(struct tt + atomic_inc(&buf->priority); + mutex_lock(&buf->lock); + } ++EXPORT_SYMBOL_GPL(tty_buffer_lock_exclusive); + + void tty_buffer_unlock_exclusive(struct tty_port *port) + { +@@ -73,6 +74,7 @@ void tty_buffer_unlock_exclusive(struct + if (restart) + queue_work(system_unbound_wq, &buf->work); + } ++EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive); + + /** + * tty_buffer_space_avail - return unused buffer space diff --git a/debian/patches/series b/debian/patches/series index 24e2a8f70..7dcc03648 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -65,6 +65,8 @@ bugfix/all/misc-bmp085-Enable-building-as-a-module.patch bugfix/all/kbuild-use-nostdinc-in-compile-tests.patch bugfix/all/disable-some-marvell-phys.patch bugfix/all/bluetooth-allocate-static-minor-for-vhci.patch +bugfix/all/0001-Staging-speakup-Move-pasting-into-a-work-item.patch +bugfix/all/0002-Staging-speakup-Update-__speakup_paste_selection-tty.patch # Miscellaneous features features/all/x86-memtest-WARN-if-bad-RAM-found.patch