From: Greg Kroah-Hartman Date: Mon, 31 Aug 2020 10:31:54 +0000 (+0200) Subject: 4.9-stable patches X-Git-Tag: v4.4.235~45 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e1b4695f1ea943f0f7316a97e748e374703fef69;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: btrfs-fix-space-cache-memory-leak-after-transaction-abort.patch fbcon-prevent-user-font-height-or-width-change-from-causing-potential-out-of-bounds-access.patch hid-i2c-hid-always-sleep-60ms-after-i2c_hid_pwr_on-commands.patch serial-8250-change-lock-order-in-serial8250_do_startup.patch serial-pl011-don-t-leak-amba_ports-entry-on-driver-register-error.patch serial-pl011-fix-oops-on-eprobe_defer.patch serial-samsung-removes-the-irq-not-found-warning.patch usb-lvtest-return-proper-error-code-in-probe.patch vt-defer-kfree-of-vc_screenbuf-in-vc_do_resize.patch vt_ioctl-change-vt_resizex-ioctl-to-check-for-error-return-from-vc_resize.patch writeback-avoid-skipping-inode-writeback.patch writeback-fix-sync-livelock-due-to-b_dirty_time-processing.patch writeback-protect-inode-i_io_list-with-inode-i_lock.patch xen-uses-irqdesc-irq_data_common-handler_data-to-store-a-per-interrupt-xen-data-pointer-which-contains-xen-specific-information.patch xhci-do-warm-reset-when-both-cas-and-xdev_resume-are-set.patch --- diff --git a/queue-4.9/btrfs-fix-space-cache-memory-leak-after-transaction-abort.patch b/queue-4.9/btrfs-fix-space-cache-memory-leak-after-transaction-abort.patch new file mode 100644 index 00000000000..d0d78ad2537 --- /dev/null +++ b/queue-4.9/btrfs-fix-space-cache-memory-leak-after-transaction-abort.patch @@ -0,0 +1,125 @@ +From bbc37d6e475eee8ffa2156ec813efc6bbb43c06d Mon Sep 17 00:00:00 2001 +From: Filipe Manana +Date: Fri, 14 Aug 2020 11:04:09 +0100 +Subject: btrfs: fix space cache memory leak after transaction abort + +From: Filipe Manana + +commit bbc37d6e475eee8ffa2156ec813efc6bbb43c06d upstream. + +If a transaction aborts it can cause a memory leak of the pages array of +a block group's io_ctl structure. The following steps explain how that can +happen: + +1) Transaction N is committing, currently in state TRANS_STATE_UNBLOCKED + and it's about to start writing out dirty extent buffers; + +2) Transaction N + 1 already started and another task, task A, just called + btrfs_commit_transaction() on it; + +3) Block group B was dirtied (extents allocated from it) by transaction + N + 1, so when task A calls btrfs_start_dirty_block_groups(), at the + very beginning of the transaction commit, it starts writeback for the + block group's space cache by calling btrfs_write_out_cache(), which + allocates the pages array for the block group's io_ctl with a call to + io_ctl_init(). Block group A is added to the io_list of transaction + N + 1 by btrfs_start_dirty_block_groups(); + +4) While transaction N's commit is writing out the extent buffers, it gets + an IO error and aborts transaction N, also setting the file system to + RO mode; + +5) Task A has already returned from btrfs_start_dirty_block_groups(), is at + btrfs_commit_transaction() and has set transaction N + 1 state to + TRANS_STATE_COMMIT_START. Immediately after that it checks that the + filesystem was turned to RO mode, due to transaction N's abort, and + jumps to the "cleanup_transaction" label. After that we end up at + btrfs_cleanup_one_transaction() which calls btrfs_cleanup_dirty_bgs(). + That helper finds block group B in the transaction's io_list but it + never releases the pages array of the block group's io_ctl, resulting in + a memory leak. + +In fact at the point when we are at btrfs_cleanup_dirty_bgs(), the pages +array points to pages that were already released by us at +__btrfs_write_out_cache() through the call to io_ctl_drop_pages(). We end +up freeing the pages array only after waiting for the ordered extent to +complete through btrfs_wait_cache_io(), which calls io_ctl_free() to do +that. But in the transaction abort case we don't wait for the space cache's +ordered extent to complete through a call to btrfs_wait_cache_io(), so +that's why we end up with a memory leak - we wait for the ordered extent +to complete indirectly by shutting down the work queues and waiting for +any jobs in them to complete before returning from close_ctree(). + +We can solve the leak simply by freeing the pages array right after +releasing the pages (with the call to io_ctl_drop_pages()) at +__btrfs_write_out_cache(), since we will never use it anymore after that +and the pages array points to already released pages at that point, which +is currently not a problem since no one will use it after that, but not a +good practice anyway since it can easily lead to use-after-free issues. + +So fix this by freeing the pages array right after releasing the pages at +__btrfs_write_out_cache(). + +This issue can often be reproduced with test case generic/475 from fstests +and kmemleak can detect it and reports it with the following trace: + +unreferenced object 0xffff9bbf009fa600 (size 512): + comm "fsstress", pid 38807, jiffies 4298504428 (age 22.028s) + hex dump (first 32 bytes): + 00 a0 7c 4d 3d ed ff ff 40 a0 7c 4d 3d ed ff ff ..|M=...@.|M=... + 80 a0 7c 4d 3d ed ff ff c0 a0 7c 4d 3d ed ff ff ..|M=.....|M=... + backtrace: + [<00000000f4b5cfe2>] __kmalloc+0x1a8/0x3e0 + [<0000000028665e7f>] io_ctl_init+0xa7/0x120 [btrfs] + [<00000000a1f95b2d>] __btrfs_write_out_cache+0x86/0x4a0 [btrfs] + [<00000000207ea1b0>] btrfs_write_out_cache+0x7f/0xf0 [btrfs] + [<00000000af21f534>] btrfs_start_dirty_block_groups+0x27b/0x580 [btrfs] + [<00000000c3c23d44>] btrfs_commit_transaction+0xa6f/0xe70 [btrfs] + [<000000009588930c>] create_subvol+0x581/0x9a0 [btrfs] + [<000000009ef2fd7f>] btrfs_mksubvol+0x3fb/0x4a0 [btrfs] + [<00000000474e5187>] __btrfs_ioctl_snap_create+0x119/0x1a0 [btrfs] + [<00000000708ee349>] btrfs_ioctl_snap_create_v2+0xb0/0xf0 [btrfs] + [<00000000ea60106f>] btrfs_ioctl+0x12c/0x3130 [btrfs] + [<000000005c923d6d>] __x64_sys_ioctl+0x83/0xb0 + [<0000000043ace2c9>] do_syscall_64+0x33/0x80 + [<00000000904efbce>] entry_SYSCALL_64_after_hwframe+0x44/0xa9 + +CC: stable@vger.kernel.org # 4.9+ +Reviewed-by: Josef Bacik +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/disk-io.c | 1 + + fs/btrfs/free-space-cache.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -4432,6 +4432,7 @@ static void btrfs_cleanup_bg_io(struct b + cache->io_ctl.inode = NULL; + iput(inode); + } ++ ASSERT(cache->io_ctl.pages == NULL); + btrfs_put_block_group(cache); + } + +--- a/fs/btrfs/free-space-cache.c ++++ b/fs/btrfs/free-space-cache.c +@@ -1165,7 +1165,6 @@ int btrfs_wait_cache_io(struct btrfs_roo + ret = update_cache_item(trans, root, inode, path, offset, + io_ctl->entries, io_ctl->bitmaps); + out: +- io_ctl_free(io_ctl); + if (ret) { + invalidate_inode_pages2(inode->i_mapping); + BTRFS_I(inode)->generation = 0; +@@ -1314,6 +1313,7 @@ static int __btrfs_write_out_cache(struc + * them out later + */ + io_ctl_drop_pages(io_ctl); ++ io_ctl_free(io_ctl); + + unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, + i_size_read(inode) - 1, &cached_state, GFP_NOFS); diff --git a/queue-4.9/fbcon-prevent-user-font-height-or-width-change-from-causing-potential-out-of-bounds-access.patch b/queue-4.9/fbcon-prevent-user-font-height-or-width-change-from-causing-potential-out-of-bounds-access.patch new file mode 100644 index 00000000000..4c7897cd221 --- /dev/null +++ b/queue-4.9/fbcon-prevent-user-font-height-or-width-change-from-causing-potential-out-of-bounds-access.patch @@ -0,0 +1,79 @@ +From 39b3cffb8cf3111738ea993e2757ab382253d86a Mon Sep 17 00:00:00 2001 +From: George Kennedy +Date: Fri, 31 Jul 2020 12:33:11 -0400 +Subject: fbcon: prevent user font height or width change from causing potential out-of-bounds access + +From: George Kennedy + +commit 39b3cffb8cf3111738ea993e2757ab382253d86a upstream. + +Add a check to fbcon_resize() to ensure that a possible change to user font +height or user font width will not allow a font data out-of-bounds access. +NOTE: must use original charcount in calculation as font charcount can +change and cannot be used to determine the font data allocated size. + +Signed-off-by: George Kennedy +Cc: stable +Reported-by: syzbot+38a3699c7eaf165b97a6@syzkaller.appspotmail.com +Link: https://lore.kernel.org/r/1596213192-6635-1-git-send-email-george.kennedy@oracle.com +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/video/console/fbcon.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +--- a/drivers/video/console/fbcon.c ++++ b/drivers/video/console/fbcon.c +@@ -2116,6 +2116,9 @@ static void updatescrollmode(struct disp + } + } + ++#define PITCH(w) (((w) + 7) >> 3) ++#define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */ ++ + static int fbcon_resize(struct vc_data *vc, unsigned int width, + unsigned int height, unsigned int user) + { +@@ -2125,6 +2128,24 @@ static int fbcon_resize(struct vc_data * + struct fb_var_screeninfo var = info->var; + int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh; + ++ if (ops->p && ops->p->userfont && FNTSIZE(vc->vc_font.data)) { ++ int size; ++ int pitch = PITCH(vc->vc_font.width); ++ ++ /* ++ * If user font, ensure that a possible change to user font ++ * height or width will not allow a font data out-of-bounds access. ++ * NOTE: must use original charcount in calculation as font ++ * charcount can change and cannot be used to determine the ++ * font data allocated size. ++ */ ++ if (pitch <= 0) ++ return -EINVAL; ++ size = CALC_FONTSZ(vc->vc_font.height, pitch, FNTCHARCNT(vc->vc_font.data)); ++ if (size > FNTSIZE(vc->vc_font.data)) ++ return -EINVAL; ++ } ++ + virt_w = FBCON_SWAP(ops->rotate, width, height); + virt_h = FBCON_SWAP(ops->rotate, height, width); + virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width, +@@ -2586,7 +2607,7 @@ static int fbcon_set_font(struct vc_data + int size; + int i, csum; + u8 *new_data, *data = font->data; +- int pitch = (font->width+7) >> 3; ++ int pitch = PITCH(font->width); + + /* Is there a reason why fbconsole couldn't handle any charcount >256? + * If not this check should be changed to charcount < 256 */ +@@ -2602,7 +2623,7 @@ static int fbcon_set_font(struct vc_data + if (fbcon_invalid_charcount(info, charcount)) + return -EINVAL; + +- size = h * pitch * charcount; ++ size = CALC_FONTSZ(h, pitch, charcount); + + new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER); + diff --git a/queue-4.9/hid-i2c-hid-always-sleep-60ms-after-i2c_hid_pwr_on-commands.patch b/queue-4.9/hid-i2c-hid-always-sleep-60ms-after-i2c_hid_pwr_on-commands.patch new file mode 100644 index 00000000000..83861bd0556 --- /dev/null +++ b/queue-4.9/hid-i2c-hid-always-sleep-60ms-after-i2c_hid_pwr_on-commands.patch @@ -0,0 +1,93 @@ +From eef4016243e94c438f177ca8226876eb873b9c75 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 11 Aug 2020 15:39:58 +0200 +Subject: HID: i2c-hid: Always sleep 60ms after I2C_HID_PWR_ON commands + +From: Hans de Goede + +commit eef4016243e94c438f177ca8226876eb873b9c75 upstream. + +Before this commit i2c_hid_parse() consists of the following steps: + +1. Send power on cmd +2. usleep_range(1000, 5000) +3. Send reset cmd +4. Wait for reset to complete (device interrupt, or msleep(100)) +5. Send power on cmd +6. Try to read HID descriptor + +Notice how there is an usleep_range(1000, 5000) after the first power-on +command, but not after the second power-on command. + +Testing has shown that at least on the BMAX Y13 laptop's i2c-hid touchpad, +not having a delay after the second power-on command causes the HID +descriptor to read as all zeros. + +In case we hit this on other devices too, the descriptor being all zeros +can be recognized by the following message being logged many, many times: + +hid-generic 0018:0911:5288.0002: unknown main item tag 0x0 + +At the same time as the BMAX Y13's touchpad issue was debugged, +Kai-Heng was working on debugging some issues with Goodix i2c-hid +touchpads. It turns out that these need a delay after a PWR_ON command +too, otherwise they stop working after a suspend/resume cycle. +According to Goodix a delay of minimal 60ms is needed. + +Having multiple cases where we need a delay after sending the power-on +command, seems to indicate that we should always sleep after the power-on +command. + +This commit fixes the mentioned issues by moving the existing 1ms sleep to +the i2c_hid_set_power() function and changing it to a 60ms sleep. + +Cc: stable@vger.kernel.org +BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=208247 +Reported-by: Kai-Heng Feng +Reported-and-tested-by: Andrea Borgia +Signed-off-by: Hans de Goede +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hid/i2c-hid/i2c-hid-core.c | 22 +++++++++++++--------- + 1 file changed, 13 insertions(+), 9 deletions(-) + +--- a/drivers/hid/i2c-hid/i2c-hid-core.c ++++ b/drivers/hid/i2c-hid/i2c-hid-core.c +@@ -407,6 +407,19 @@ static int i2c_hid_set_power(struct i2c_ + dev_err(&client->dev, "failed to change power setting.\n"); + + set_pwr_exit: ++ ++ /* ++ * The HID over I2C specification states that if a DEVICE needs time ++ * after the PWR_ON request, it should utilise CLOCK stretching. ++ * However, it has been observered that the Windows driver provides a ++ * 1ms sleep between the PWR_ON and RESET requests. ++ * According to Goodix Windows even waits 60 ms after (other?) ++ * PWR_ON requests. Testing has confirmed that several devices ++ * will not work properly without a delay after a PWR_ON request. ++ */ ++ if (!ret && power_state == I2C_HID_PWR_ON) ++ msleep(60); ++ + return ret; + } + +@@ -428,15 +441,6 @@ static int i2c_hid_hwreset(struct i2c_cl + if (ret) + goto out_unlock; + +- /* +- * The HID over I2C specification states that if a DEVICE needs time +- * after the PWR_ON request, it should utilise CLOCK stretching. +- * However, it has been observered that the Windows driver provides a +- * 1ms sleep between the PWR_ON and RESET requests and that some devices +- * rely on this. +- */ +- usleep_range(1000, 5000); +- + i2c_hid_dbg(ihid, "resetting...\n"); + + ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0); diff --git a/queue-4.9/serial-8250-change-lock-order-in-serial8250_do_startup.patch b/queue-4.9/serial-8250-change-lock-order-in-serial8250_do_startup.patch new file mode 100644 index 00000000000..55858646e04 --- /dev/null +++ b/queue-4.9/serial-8250-change-lock-order-in-serial8250_do_startup.patch @@ -0,0 +1,215 @@ +From 205d300aea75623e1ae4aa43e0d265ab9cf195fd Mon Sep 17 00:00:00 2001 +From: Sergey Senozhatsky +Date: Mon, 17 Aug 2020 11:26:46 +0900 +Subject: serial: 8250: change lock order in serial8250_do_startup() + +From: Sergey Senozhatsky + +commit 205d300aea75623e1ae4aa43e0d265ab9cf195fd upstream. + +We have a number of "uart.port->desc.lock vs desc.lock->uart.port" +lockdep reports coming from 8250 driver; this causes a bit of trouble +to people, so let's fix it. + +The problem is reverse lock order in two different call paths: + +chain #1: + + serial8250_do_startup() + spin_lock_irqsave(&port->lock); + disable_irq_nosync(port->irq); + raw_spin_lock_irqsave(&desc->lock) + +chain #2: + + __report_bad_irq() + raw_spin_lock_irqsave(&desc->lock) + for_each_action_of_desc() + printk() + spin_lock_irqsave(&port->lock); + +Fix this by changing the order of locks in serial8250_do_startup(): + do disable_irq_nosync() first, which grabs desc->lock, and grab + uart->port after that, so that chain #1 and chain #2 have same lock + order. + +Full lockdep splat: + + ====================================================== + WARNING: possible circular locking dependency detected + 5.4.39 #55 Not tainted + ====================================================== + + swapper/0/0 is trying to acquire lock: + ffffffffab65b6c0 (console_owner){-...}, at: console_lock_spinning_enable+0x31/0x57 + + but task is already holding lock: + ffff88810a8e34c0 (&irq_desc_lock_class){-.-.}, at: __report_bad_irq+0x5b/0xba + + which lock already depends on the new lock. + + the existing dependency chain (in reverse order) is: + + -> #2 (&irq_desc_lock_class){-.-.}: + _raw_spin_lock_irqsave+0x61/0x8d + __irq_get_desc_lock+0x65/0x89 + __disable_irq_nosync+0x3b/0x93 + serial8250_do_startup+0x451/0x75c + uart_startup+0x1b4/0x2ff + uart_port_activate+0x73/0xa0 + tty_port_open+0xae/0x10a + uart_open+0x1b/0x26 + tty_open+0x24d/0x3a0 + chrdev_open+0xd5/0x1cc + do_dentry_open+0x299/0x3c8 + path_openat+0x434/0x1100 + do_filp_open+0x9b/0x10a + do_sys_open+0x15f/0x3d7 + kernel_init_freeable+0x157/0x1dd + kernel_init+0xe/0x105 + ret_from_fork+0x27/0x50 + + -> #1 (&port_lock_key){-.-.}: + _raw_spin_lock_irqsave+0x61/0x8d + serial8250_console_write+0xa7/0x2a0 + console_unlock+0x3b7/0x528 + vprintk_emit+0x111/0x17f + printk+0x59/0x73 + register_console+0x336/0x3a4 + uart_add_one_port+0x51b/0x5be + serial8250_register_8250_port+0x454/0x55e + dw8250_probe+0x4dc/0x5b9 + platform_drv_probe+0x67/0x8b + really_probe+0x14a/0x422 + driver_probe_device+0x66/0x130 + device_driver_attach+0x42/0x5b + __driver_attach+0xca/0x139 + bus_for_each_dev+0x97/0xc9 + bus_add_driver+0x12b/0x228 + driver_register+0x64/0xed + do_one_initcall+0x20c/0x4a6 + do_initcall_level+0xb5/0xc5 + do_basic_setup+0x4c/0x58 + kernel_init_freeable+0x13f/0x1dd + kernel_init+0xe/0x105 + ret_from_fork+0x27/0x50 + + -> #0 (console_owner){-...}: + __lock_acquire+0x118d/0x2714 + lock_acquire+0x203/0x258 + console_lock_spinning_enable+0x51/0x57 + console_unlock+0x25d/0x528 + vprintk_emit+0x111/0x17f + printk+0x59/0x73 + __report_bad_irq+0xa3/0xba + note_interrupt+0x19a/0x1d6 + handle_irq_event_percpu+0x57/0x79 + handle_irq_event+0x36/0x55 + handle_fasteoi_irq+0xc2/0x18a + do_IRQ+0xb3/0x157 + ret_from_intr+0x0/0x1d + cpuidle_enter_state+0x12f/0x1fd + cpuidle_enter+0x2e/0x3d + do_idle+0x1ce/0x2ce + cpu_startup_entry+0x1d/0x1f + start_kernel+0x406/0x46a + secondary_startup_64+0xa4/0xb0 + + other info that might help us debug this: + + Chain exists of: + console_owner --> &port_lock_key --> &irq_desc_lock_class + + Possible unsafe locking scenario: + + CPU0 CPU1 + ---- ---- + lock(&irq_desc_lock_class); + lock(&port_lock_key); + lock(&irq_desc_lock_class); + lock(console_owner); + + *** DEADLOCK *** + + 2 locks held by swapper/0/0: + #0: ffff88810a8e34c0 (&irq_desc_lock_class){-.-.}, at: __report_bad_irq+0x5b/0xba + #1: ffffffffab65b5c0 (console_lock){+.+.}, at: console_trylock_spinning+0x20/0x181 + + stack backtrace: + CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.4.39 #55 + Hardware name: XXXXXX + Call Trace: + + dump_stack+0xbf/0x133 + ? print_circular_bug+0xd6/0xe9 + check_noncircular+0x1b9/0x1c3 + __lock_acquire+0x118d/0x2714 + lock_acquire+0x203/0x258 + ? console_lock_spinning_enable+0x31/0x57 + console_lock_spinning_enable+0x51/0x57 + ? console_lock_spinning_enable+0x31/0x57 + console_unlock+0x25d/0x528 + ? console_trylock+0x18/0x4e + vprintk_emit+0x111/0x17f + ? lock_acquire+0x203/0x258 + printk+0x59/0x73 + __report_bad_irq+0xa3/0xba + note_interrupt+0x19a/0x1d6 + handle_irq_event_percpu+0x57/0x79 + handle_irq_event+0x36/0x55 + handle_fasteoi_irq+0xc2/0x18a + do_IRQ+0xb3/0x157 + common_interrupt+0xf/0xf + + +Signed-off-by: Sergey Senozhatsky +Fixes: 768aec0b5bcc ("serial: 8250: fix shared interrupts issues with SMP and RT kernels") +Reported-by: Guenter Roeck +Reported-by: Raul Rangel +BugLink: https://bugs.chromium.org/p/chromium/issues/detail?id=1114800 +Link: https://lore.kernel.org/lkml/CAHQZ30BnfX+gxjPm1DUd5psOTqbyDh4EJE=2=VAMW_VDafctkA@mail.gmail.com/T/#u +Reviewed-by: Andy Shevchenko +Reviewed-by: Guenter Roeck +Tested-by: Guenter Roeck +Cc: stable +Link: https://lore.kernel.org/r/20200817022646.1484638-1-sergey.senozhatsky@gmail.com +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/serial/8250/8250_port.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -2205,6 +2205,10 @@ int serial8250_do_startup(struct uart_po + + if (port->irq) { + unsigned char iir1; ++ ++ if (port->irqflags & IRQF_SHARED) ++ disable_irq_nosync(port->irq); ++ + /* + * Test for UARTs that do not reassert THRE when the + * transmitter is idle and the interrupt has already +@@ -2214,8 +2218,6 @@ int serial8250_do_startup(struct uart_po + * allow register changes to become visible. + */ + spin_lock_irqsave(&port->lock, flags); +- if (up->port.irqflags & IRQF_SHARED) +- disable_irq_nosync(port->irq); + + wait_for_xmitr(up, UART_LSR_THRE); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); +@@ -2227,9 +2229,10 @@ int serial8250_do_startup(struct uart_po + iir = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); + ++ spin_unlock_irqrestore(&port->lock, flags); ++ + if (port->irqflags & IRQF_SHARED) + enable_irq(port->irq); +- spin_unlock_irqrestore(&port->lock, flags); + + /* + * If the interrupt is not reasserted, or we otherwise diff --git a/queue-4.9/serial-pl011-don-t-leak-amba_ports-entry-on-driver-register-error.patch b/queue-4.9/serial-pl011-don-t-leak-amba_ports-entry-on-driver-register-error.patch new file mode 100644 index 00000000000..e4b8576f4e5 --- /dev/null +++ b/queue-4.9/serial-pl011-don-t-leak-amba_ports-entry-on-driver-register-error.patch @@ -0,0 +1,52 @@ +From 89efbe70b27dd325d8a8c177743a26b885f7faec Mon Sep 17 00:00:00 2001 +From: Lukas Wunner +Date: Thu, 13 Aug 2020 12:59:54 +0200 +Subject: serial: pl011: Don't leak amba_ports entry on driver register error + +From: Lukas Wunner + +commit 89efbe70b27dd325d8a8c177743a26b885f7faec upstream. + +pl011_probe() calls pl011_setup_port() to reserve an amba_ports[] entry, +then calls pl011_register_port() to register the uart driver with the +tty layer. + +If registration of the uart driver fails, the amba_ports[] entry is not +released. If this happens 14 times (value of UART_NR macro), then all +amba_ports[] entries will have been leaked and driver probing is no +longer possible. (To be fair, that can only happen if the DeviceTree +doesn't contain alias IDs since they cause the same entry to be used for +a given port.) Fix it. + +Fixes: ef2889f7ffee ("serial: pl011: Move uart_register_driver call to device") +Signed-off-by: Lukas Wunner +Cc: stable@vger.kernel.org # v3.15+ +Cc: Tushar Behera +Link: https://lore.kernel.org/r/138f8c15afb2f184d8102583f8301575566064a6.1597316167.git.lukas@wunner.de +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/serial/amba-pl011.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -2532,7 +2532,7 @@ static int pl011_setup_port(struct devic + + static int pl011_register_port(struct uart_amba_port *uap) + { +- int ret; ++ int ret, i; + + /* Ensure interrupts from this UART are masked and cleared */ + pl011_write(0, uap, REG_IMSC); +@@ -2543,6 +2543,9 @@ static int pl011_register_port(struct ua + if (ret < 0) { + dev_err(uap->port.dev, + "Failed to register AMBA-PL011 driver\n"); ++ for (i = 0; i < ARRAY_SIZE(amba_ports); i++) ++ if (amba_ports[i] == uap) ++ amba_ports[i] = NULL; + return ret; + } + } diff --git a/queue-4.9/serial-pl011-fix-oops-on-eprobe_defer.patch b/queue-4.9/serial-pl011-fix-oops-on-eprobe_defer.patch new file mode 100644 index 00000000000..749f181eb2e --- /dev/null +++ b/queue-4.9/serial-pl011-fix-oops-on-eprobe_defer.patch @@ -0,0 +1,93 @@ +From 27afac93e3bd7fa89749cf11da5d86ac9cde4dba Mon Sep 17 00:00:00 2001 +From: Lukas Wunner +Date: Thu, 13 Aug 2020 12:52:40 +0200 +Subject: serial: pl011: Fix oops on -EPROBE_DEFER + +From: Lukas Wunner + +commit 27afac93e3bd7fa89749cf11da5d86ac9cde4dba upstream. + +If probing of a pl011 gets deferred until after free_initmem(), an oops +ensues because pl011_console_match() is called which has been freed. + +Fix by removing the __init attribute from the function and those it +calls. + +Commit 10879ae5f12e ("serial: pl011: add console matching function") +introduced pl011_console_match() not just for early consoles but +regular preferred consoles, such as those added by acpi_parse_spcr(). +Regular consoles may be registered after free_initmem() for various +reasons, one being deferred probing, another being dynamic enablement +of serial ports using a DeviceTree overlay. + +Thus, pl011_console_match() must not be declared __init and the +functions it calls mustn't either. + +Stack trace for posterity: + +Unable to handle kernel paging request at virtual address 80c38b58 +Internal error: Oops: 8000000d [#1] PREEMPT SMP ARM +PC is at pl011_console_match+0x0/0xfc +LR is at register_console+0x150/0x468 +[<80187004>] (register_console) +[<805a8184>] (uart_add_one_port) +[<805b2b68>] (pl011_register_port) +[<805b3ce4>] (pl011_probe) +[<80569214>] (amba_probe) +[<805ca088>] (really_probe) +[<805ca2ec>] (driver_probe_device) +[<805ca5b0>] (__device_attach_driver) +[<805c8060>] (bus_for_each_drv) +[<805c9dfc>] (__device_attach) +[<805ca630>] (device_initial_probe) +[<805c90a8>] (bus_probe_device) +[<805c95a8>] (deferred_probe_work_func) + +Fixes: 10879ae5f12e ("serial: pl011: add console matching function") +Signed-off-by: Lukas Wunner +Cc: stable@vger.kernel.org # v4.10+ +Cc: Aleksey Makarov +Cc: Peter Hurley +Cc: Russell King +Cc: Christopher Covington +Link: https://lore.kernel.org/r/f827ff09da55b8c57d316a1b008a137677b58921.1597315557.git.lukas@wunner.de +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/serial/amba-pl011.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -2249,9 +2249,8 @@ pl011_console_write(struct console *co, + clk_disable(uap->clk); + } + +-static void __init +-pl011_console_get_options(struct uart_amba_port *uap, int *baud, +- int *parity, int *bits) ++static void pl011_console_get_options(struct uart_amba_port *uap, int *baud, ++ int *parity, int *bits) + { + if (pl011_read(uap, REG_CR) & UART01x_CR_UARTEN) { + unsigned int lcr_h, ibrd, fbrd; +@@ -2284,7 +2283,7 @@ pl011_console_get_options(struct uart_am + } + } + +-static int __init pl011_console_setup(struct console *co, char *options) ++static int pl011_console_setup(struct console *co, char *options) + { + struct uart_amba_port *uap; + int baud = 38400; +@@ -2352,8 +2351,8 @@ static int __init pl011_console_setup(st + * + * Returns 0 if console matches; otherwise non-zero to use default matching + */ +-static int __init pl011_console_match(struct console *co, char *name, int idx, +- char *options) ++static int pl011_console_match(struct console *co, char *name, int idx, ++ char *options) + { + unsigned char iotype; + resource_size_t addr; diff --git a/queue-4.9/serial-samsung-removes-the-irq-not-found-warning.patch b/queue-4.9/serial-samsung-removes-the-irq-not-found-warning.patch new file mode 100644 index 00000000000..e6047db36c3 --- /dev/null +++ b/queue-4.9/serial-samsung-removes-the-irq-not-found-warning.patch @@ -0,0 +1,50 @@ +From 8c6c378b0cbe0c9f1390986b5f8ffb5f6ff7593b Mon Sep 17 00:00:00 2001 +From: Tamseel Shams +Date: Mon, 10 Aug 2020 08:30:21 +0530 +Subject: serial: samsung: Removes the IRQ not found warning + +From: Tamseel Shams + +commit 8c6c378b0cbe0c9f1390986b5f8ffb5f6ff7593b upstream. + +In few older Samsung SoCs like s3c2410, s3c2412 +and s3c2440, UART IP is having 2 interrupt lines. +However, in other SoCs like s3c6400, s5pv210, +exynos5433, and exynos4210 UART is having only 1 +interrupt line. Due to this, "platform_get_irq(platdev, 1)" +call in the driver gives the following false-positive error: +"IRQ index 1 not found" on newer SoC's. + +This patch adds the condition to check for Tx interrupt +only for the those SoC's which have 2 interrupt lines. + +Tested-by: Alim Akhtar +Tested-by: Marek Szyprowski +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Alim Akhtar +Signed-off-by: Tamseel Shams +Cc: stable +Link: https://lore.kernel.org/r/20200810030021.45348-1-m.shams@samsung.com +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/serial/samsung.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/tty/serial/samsung.c ++++ b/drivers/tty/serial/samsung.c +@@ -1725,9 +1725,11 @@ static int s3c24xx_serial_init_port(stru + ourport->tx_irq = ret + 1; + } + +- ret = platform_get_irq(platdev, 1); +- if (ret > 0) +- ourport->tx_irq = ret; ++ if (!s3c24xx_serial_has_interrupt_mask(port)) { ++ ret = platform_get_irq(platdev, 1); ++ if (ret > 0) ++ ourport->tx_irq = ret; ++ } + /* + * DMA is currently supported only on DT platforms, if DMA properties + * are specified. diff --git a/queue-4.9/series b/queue-4.9/series index e29d5142135..26589982737 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -46,3 +46,18 @@ scsi-ufs-fix-possible-infinite-loop-in-ufshcd_hold.patch scsi-ufs-improve-interrupt-handling-for-shared-inter.patch net-gianfar-add-of_node_put-before-goto-statement.patch powerpc-perf-fix-soft-lockups-due-to-missed-interrup.patch +hid-i2c-hid-always-sleep-60ms-after-i2c_hid_pwr_on-commands.patch +btrfs-fix-space-cache-memory-leak-after-transaction-abort.patch +fbcon-prevent-user-font-height-or-width-change-from-causing-potential-out-of-bounds-access.patch +usb-lvtest-return-proper-error-code-in-probe.patch +vt-defer-kfree-of-vc_screenbuf-in-vc_do_resize.patch +vt_ioctl-change-vt_resizex-ioctl-to-check-for-error-return-from-vc_resize.patch +serial-samsung-removes-the-irq-not-found-warning.patch +serial-pl011-fix-oops-on-eprobe_defer.patch +serial-pl011-don-t-leak-amba_ports-entry-on-driver-register-error.patch +serial-8250-change-lock-order-in-serial8250_do_startup.patch +writeback-protect-inode-i_io_list-with-inode-i_lock.patch +writeback-avoid-skipping-inode-writeback.patch +writeback-fix-sync-livelock-due-to-b_dirty_time-processing.patch +xen-uses-irqdesc-irq_data_common-handler_data-to-store-a-per-interrupt-xen-data-pointer-which-contains-xen-specific-information.patch +xhci-do-warm-reset-when-both-cas-and-xdev_resume-are-set.patch diff --git a/queue-4.9/usb-lvtest-return-proper-error-code-in-probe.patch b/queue-4.9/usb-lvtest-return-proper-error-code-in-probe.patch new file mode 100644 index 00000000000..b98c5900544 --- /dev/null +++ b/queue-4.9/usb-lvtest-return-proper-error-code-in-probe.patch @@ -0,0 +1,35 @@ +From 531412492ce93ea29b9ca3b4eb5e3ed771f851dd Mon Sep 17 00:00:00 2001 +From: Evgeny Novikov +Date: Wed, 5 Aug 2020 12:06:43 +0300 +Subject: USB: lvtest: return proper error code in probe + +From: Evgeny Novikov + +commit 531412492ce93ea29b9ca3b4eb5e3ed771f851dd upstream. + +lvs_rh_probe() can return some nonnegative value from usb_control_msg() +when it is less than "USB_DT_HUB_NONVAR_SIZE + 2" that is considered as +a failure. Make lvs_rh_probe() return -EINVAL in this case. + +Found by Linux Driver Verification project (linuxtesting.org). + +Signed-off-by: Evgeny Novikov +Cc: stable +Link: https://lore.kernel.org/r/20200805090643.3432-1-novikov@ispras.ru +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/misc/lvstest.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/misc/lvstest.c ++++ b/drivers/usb/misc/lvstest.c +@@ -392,7 +392,7 @@ static int lvs_rh_probe(struct usb_inter + USB_DT_SS_HUB_SIZE, USB_CTRL_GET_TIMEOUT); + if (ret < (USB_DT_HUB_NONVAR_SIZE + 2)) { + dev_err(&hdev->dev, "wrong root hub descriptor read %d\n", ret); +- return ret; ++ return ret < 0 ? ret : -EINVAL; + } + + /* submit urb to poll interrupt endpoint */ diff --git a/queue-4.9/vt-defer-kfree-of-vc_screenbuf-in-vc_do_resize.patch b/queue-4.9/vt-defer-kfree-of-vc_screenbuf-in-vc_do_resize.patch new file mode 100644 index 00000000000..5719ba1640c --- /dev/null +++ b/queue-4.9/vt-defer-kfree-of-vc_screenbuf-in-vc_do_resize.patch @@ -0,0 +1,57 @@ +From f8d1653daec02315e06d30246cff4af72e76e54e Mon Sep 17 00:00:00 2001 +From: Tetsuo Handa +Date: Wed, 29 Jul 2020 23:57:01 +0900 +Subject: vt: defer kfree() of vc_screenbuf in vc_do_resize() + +From: Tetsuo Handa + +commit f8d1653daec02315e06d30246cff4af72e76e54e upstream. + +syzbot is reporting UAF bug in set_origin() from vc_do_resize() [1], for +vc_do_resize() calls kfree(vc->vc_screenbuf) before calling set_origin(). + +Unfortunately, in set_origin(), vc->vc_sw->con_set_origin() might access +vc->vc_pos when scroll is involved in order to manipulate cursor, but +vc->vc_pos refers already released vc->vc_screenbuf until vc->vc_pos gets +updated based on the result of vc->vc_sw->con_set_origin(). + +Preserving old buffer and tolerating outdated vc members until set_origin() +completes would be easier than preventing vc->vc_sw->con_set_origin() from +accessing outdated vc members. + +[1] https://syzkaller.appspot.com/bug?id=6649da2081e2ebdc65c0642c214b27fe91099db3 + +Reported-by: syzbot +Signed-off-by: Tetsuo Handa +Cc: stable +Link: https://lore.kernel.org/r/1596034621-4714-1-git-send-email-penguin-kernel@I-love.SAKURA.ne.jp +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/vt/vt.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/tty/vt/vt.c ++++ b/drivers/tty/vt/vt.c +@@ -868,7 +868,7 @@ static int vc_do_resize(struct tty_struc + unsigned int old_rows, old_row_size; + unsigned int new_cols, new_rows, new_row_size, new_screen_size; + unsigned int user; +- unsigned short *newscreen; ++ unsigned short *oldscreen, *newscreen; + + WARN_CONSOLE_UNLOCKED(); + +@@ -950,10 +950,11 @@ static int vc_do_resize(struct tty_struc + if (new_scr_end > new_origin) + scr_memsetw((void *)new_origin, vc->vc_video_erase_char, + new_scr_end - new_origin); +- kfree(vc->vc_screenbuf); ++ oldscreen = vc->vc_screenbuf; + vc->vc_screenbuf = newscreen; + vc->vc_screenbuf_size = new_screen_size; + set_origin(vc); ++ kfree(oldscreen); + + /* do part of a reset_terminal() */ + vc->vc_top = 0; diff --git a/queue-4.9/vt_ioctl-change-vt_resizex-ioctl-to-check-for-error-return-from-vc_resize.patch b/queue-4.9/vt_ioctl-change-vt_resizex-ioctl-to-check-for-error-return-from-vc_resize.patch new file mode 100644 index 00000000000..8fc6bc1d19c --- /dev/null +++ b/queue-4.9/vt_ioctl-change-vt_resizex-ioctl-to-check-for-error-return-from-vc_resize.patch @@ -0,0 +1,49 @@ +From bc5269ca765057a1b762e79a1cfd267cd7bf1c46 Mon Sep 17 00:00:00 2001 +From: George Kennedy +Date: Fri, 31 Jul 2020 12:33:12 -0400 +Subject: vt_ioctl: change VT_RESIZEX ioctl to check for error return from vc_resize() + +From: George Kennedy + +commit bc5269ca765057a1b762e79a1cfd267cd7bf1c46 upstream. + +vc_resize() can return with an error after failure. Change VT_RESIZEX ioctl +to save struct vc_data values that are modified and restore the original +values in case of error. + +Signed-off-by: George Kennedy +Cc: stable +Reported-by: syzbot+38a3699c7eaf165b97a6@syzkaller.appspotmail.com +Link: https://lore.kernel.org/r/1596213192-6635-2-git-send-email-george.kennedy@oracle.com +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/vt/vt_ioctl.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +--- a/drivers/tty/vt/vt_ioctl.c ++++ b/drivers/tty/vt/vt_ioctl.c +@@ -896,12 +896,22 @@ int vt_ioctl(struct tty_struct *tty, + console_lock(); + vcp = vc_cons[i].d; + if (vcp) { ++ int ret; ++ int save_scan_lines = vcp->vc_scan_lines; ++ int save_font_height = vcp->vc_font.height; ++ + if (v.v_vlin) + vcp->vc_scan_lines = v.v_vlin; + if (v.v_clin) + vcp->vc_font.height = v.v_clin; + vcp->vc_resize_user = 1; +- vc_resize(vcp, v.v_cols, v.v_rows); ++ ret = vc_resize(vcp, v.v_cols, v.v_rows); ++ if (ret) { ++ vcp->vc_scan_lines = save_scan_lines; ++ vcp->vc_font.height = save_font_height; ++ console_unlock(); ++ return ret; ++ } + } + console_unlock(); + } diff --git a/queue-4.9/writeback-avoid-skipping-inode-writeback.patch b/queue-4.9/writeback-avoid-skipping-inode-writeback.patch new file mode 100644 index 00000000000..10f1185a671 --- /dev/null +++ b/queue-4.9/writeback-avoid-skipping-inode-writeback.patch @@ -0,0 +1,146 @@ +From 5afced3bf28100d81fb2fe7e98918632a08feaf5 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Fri, 29 May 2020 15:05:22 +0200 +Subject: writeback: Avoid skipping inode writeback + +From: Jan Kara + +commit 5afced3bf28100d81fb2fe7e98918632a08feaf5 upstream. + +Inode's i_io_list list head is used to attach inode to several different +lists - wb->{b_dirty, b_dirty_time, b_io, b_more_io}. When flush worker +prepares a list of inodes to writeback e.g. for sync(2), it moves inodes +to b_io list. Thus it is critical for sync(2) data integrity guarantees +that inode is not requeued to any other writeback list when inode is +queued for processing by flush worker. That's the reason why +writeback_single_inode() does not touch i_io_list (unless the inode is +completely clean) and why __mark_inode_dirty() does not touch i_io_list +if I_SYNC flag is set. + +However there are two flaws in the current logic: + +1) When inode has only I_DIRTY_TIME set but it is already queued in b_io +list due to sync(2), concurrent __mark_inode_dirty(inode, I_DIRTY_SYNC) +can still move inode back to b_dirty list resulting in skipping +writeback of inode time stamps during sync(2). + +2) When inode is on b_dirty_time list and writeback_single_inode() races +with __mark_inode_dirty() like: + +writeback_single_inode() __mark_inode_dirty(inode, I_DIRTY_PAGES) + inode->i_state |= I_SYNC + __writeback_single_inode() + inode->i_state |= I_DIRTY_PAGES; + if (inode->i_state & I_SYNC) + bail + if (!(inode->i_state & I_DIRTY_ALL)) + - not true so nothing done + +We end up with I_DIRTY_PAGES inode on b_dirty_time list and thus +standard background writeback will not writeback this inode leading to +possible dirty throttling stalls etc. (thanks to Martijn Coenen for this +analysis). + +Fix these problems by tracking whether inode is queued in b_io or +b_more_io lists in a new I_SYNC_QUEUED flag. When this flag is set, we +know flush worker has queued inode and we should not touch i_io_list. +On the other hand we also know that once flush worker is done with the +inode it will requeue the inode to appropriate dirty list. When +I_SYNC_QUEUED is not set, __mark_inode_dirty() can (and must) move inode +to appropriate dirty list. + +Reported-by: Martijn Coenen +Reviewed-by: Martijn Coenen +Tested-by: Martijn Coenen +Reviewed-by: Christoph Hellwig +Fixes: 0ae45f63d4ef ("vfs: add support for a lazytime mount option") +CC: stable@vger.kernel.org +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fs-writeback.c | 17 ++++++++++++----- + include/linux/fs.h | 8 ++++++-- + 2 files changed, 18 insertions(+), 7 deletions(-) + +--- a/fs/fs-writeback.c ++++ b/fs/fs-writeback.c +@@ -162,6 +162,7 @@ static void inode_io_list_del_locked(str + assert_spin_locked(&wb->list_lock); + assert_spin_locked(&inode->i_lock); + ++ inode->i_state &= ~I_SYNC_QUEUED; + list_del_init(&inode->i_io_list); + wb_io_lists_depopulated(wb); + } +@@ -1103,6 +1104,7 @@ static void redirty_tail_locked(struct i + inode->dirtied_when = jiffies; + } + inode_io_list_move_locked(inode, wb, &wb->b_dirty); ++ inode->i_state &= ~I_SYNC_QUEUED; + } + + static void redirty_tail(struct inode *inode, struct bdi_writeback *wb) +@@ -1178,8 +1180,11 @@ static int move_expired_inodes(struct li + break; + list_move(&inode->i_io_list, &tmp); + moved++; ++ spin_lock(&inode->i_lock); + if (flags & EXPIRE_DIRTY_ATIME) +- set_bit(__I_DIRTY_TIME_EXPIRED, &inode->i_state); ++ inode->i_state |= I_DIRTY_TIME_EXPIRED; ++ inode->i_state |= I_SYNC_QUEUED; ++ spin_unlock(&inode->i_lock); + if (sb_is_blkdev_sb(inode->i_sb)) + continue; + if (sb && sb != inode->i_sb) +@@ -1354,6 +1359,7 @@ static void requeue_inode(struct inode * + } else if (inode->i_state & I_DIRTY_TIME) { + inode->dirtied_when = jiffies; + inode_io_list_move_locked(inode, wb, &wb->b_dirty_time); ++ inode->i_state &= ~I_SYNC_QUEUED; + } else { + /* The inode is clean. Remove from writeback lists. */ + inode_io_list_del_locked(inode, wb); +@@ -2188,11 +2194,12 @@ void __mark_inode_dirty(struct inode *in + inode->i_state |= flags; + + /* +- * If the inode is being synced, just update its dirty state. +- * The unlocker will place the inode on the appropriate +- * superblock list, based upon its state. ++ * If the inode is queued for writeback by flush worker, just ++ * update its dirty state. Once the flush worker is done with ++ * the inode it will place it on the appropriate superblock ++ * list, based upon its state. + */ +- if (inode->i_state & I_SYNC) ++ if (inode->i_state & I_SYNC_QUEUED) + goto out_unlock_inode; + + /* +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1954,6 +1954,10 @@ static inline bool HAS_UNMAPPED_ID(struc + * wb stat updates to grab mapping->tree_lock. See + * inode_switch_wb_work_fn() for details. + * ++ * I_SYNC_QUEUED Inode is queued in b_io or b_more_io writeback lists. ++ * Used to detect that mark_inode_dirty() should not move ++ * inode between dirty lists. ++ * + * Q: What is the difference between I_WILL_FREE and I_FREEING? + */ + #define I_DIRTY_SYNC (1 << 0) +@@ -1971,9 +1975,9 @@ static inline bool HAS_UNMAPPED_ID(struc + #define I_DIO_WAKEUP (1 << __I_DIO_WAKEUP) + #define I_LINKABLE (1 << 10) + #define I_DIRTY_TIME (1 << 11) +-#define __I_DIRTY_TIME_EXPIRED 12 +-#define I_DIRTY_TIME_EXPIRED (1 << __I_DIRTY_TIME_EXPIRED) ++#define I_DIRTY_TIME_EXPIRED (1 << 12) + #define I_WB_SWITCH (1 << 13) ++#define I_SYNC_QUEUED (1 << 17) + + #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES) + #define I_DIRTY_ALL (I_DIRTY | I_DIRTY_TIME) diff --git a/queue-4.9/writeback-fix-sync-livelock-due-to-b_dirty_time-processing.patch b/queue-4.9/writeback-fix-sync-livelock-due-to-b_dirty_time-processing.patch new file mode 100644 index 00000000000..e423fbc7fe8 --- /dev/null +++ b/queue-4.9/writeback-fix-sync-livelock-due-to-b_dirty_time-processing.patch @@ -0,0 +1,193 @@ +From f9cae926f35e8230330f28c7b743ad088611a8de Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Fri, 29 May 2020 16:08:58 +0200 +Subject: writeback: Fix sync livelock due to b_dirty_time processing + +From: Jan Kara + +commit f9cae926f35e8230330f28c7b743ad088611a8de upstream. + +When we are processing writeback for sync(2), move_expired_inodes() +didn't set any inode expiry value (older_than_this). This can result in +writeback never completing if there's steady stream of inodes added to +b_dirty_time list as writeback rechecks dirty lists after each writeback +round whether there's more work to be done. Fix the problem by using +sync(2) start time is inode expiry value when processing b_dirty_time +list similarly as for ordinarily dirtied inodes. This requires some +refactoring of older_than_this handling which simplifies the code +noticeably as a bonus. + +Fixes: 0ae45f63d4ef ("vfs: add support for a lazytime mount option") +CC: stable@vger.kernel.org +Reviewed-by: Christoph Hellwig +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fs-writeback.c | 44 +++++++++++++++------------------------ + include/trace/events/writeback.h | 13 +++++------ + 2 files changed, 23 insertions(+), 34 deletions(-) + +--- a/fs/fs-writeback.c ++++ b/fs/fs-writeback.c +@@ -45,7 +45,6 @@ struct wb_completion { + struct wb_writeback_work { + long nr_pages; + struct super_block *sb; +- unsigned long *older_than_this; + enum writeback_sync_modes sync_mode; + unsigned int tagged_writepages:1; + unsigned int for_kupdate:1; +@@ -1150,16 +1149,13 @@ static bool inode_dirtied_after(struct i + #define EXPIRE_DIRTY_ATIME 0x0001 + + /* +- * Move expired (dirtied before work->older_than_this) dirty inodes from ++ * Move expired (dirtied before dirtied_before) dirty inodes from + * @delaying_queue to @dispatch_queue. + */ + static int move_expired_inodes(struct list_head *delaying_queue, + struct list_head *dispatch_queue, +- int flags, +- struct wb_writeback_work *work) ++ int flags, unsigned long dirtied_before) + { +- unsigned long *older_than_this = NULL; +- unsigned long expire_time; + LIST_HEAD(tmp); + struct list_head *pos, *node; + struct super_block *sb = NULL; +@@ -1167,16 +1163,9 @@ static int move_expired_inodes(struct li + int do_sb_sort = 0; + int moved = 0; + +- if ((flags & EXPIRE_DIRTY_ATIME) == 0) +- older_than_this = work->older_than_this; +- else if (!work->for_sync) { +- expire_time = jiffies - (dirtytime_expire_interval * HZ); +- older_than_this = &expire_time; +- } + while (!list_empty(delaying_queue)) { + inode = wb_inode(delaying_queue->prev); +- if (older_than_this && +- inode_dirtied_after(inode, *older_than_this)) ++ if (inode_dirtied_after(inode, dirtied_before)) + break; + list_move(&inode->i_io_list, &tmp); + moved++; +@@ -1222,18 +1211,22 @@ out: + * | + * +--> dequeue for IO + */ +-static void queue_io(struct bdi_writeback *wb, struct wb_writeback_work *work) ++static void queue_io(struct bdi_writeback *wb, struct wb_writeback_work *work, ++ unsigned long dirtied_before) + { + int moved; ++ unsigned long time_expire_jif = dirtied_before; + + assert_spin_locked(&wb->list_lock); + list_splice_init(&wb->b_more_io, &wb->b_io); +- moved = move_expired_inodes(&wb->b_dirty, &wb->b_io, 0, work); ++ moved = move_expired_inodes(&wb->b_dirty, &wb->b_io, 0, dirtied_before); ++ if (!work->for_sync) ++ time_expire_jif = jiffies - dirtytime_expire_interval * HZ; + moved += move_expired_inodes(&wb->b_dirty_time, &wb->b_io, +- EXPIRE_DIRTY_ATIME, work); ++ EXPIRE_DIRTY_ATIME, time_expire_jif); + if (moved) + wb_io_lists_populated(wb); +- trace_writeback_queue_io(wb, work, moved); ++ trace_writeback_queue_io(wb, work, dirtied_before, moved); + } + + static int write_inode(struct inode *inode, struct writeback_control *wbc) +@@ -1745,7 +1738,7 @@ static long writeback_inodes_wb(struct b + blk_start_plug(&plug); + spin_lock(&wb->list_lock); + if (list_empty(&wb->b_io)) +- queue_io(wb, &work); ++ queue_io(wb, &work, jiffies); + __writeback_inodes_wb(wb, &work); + spin_unlock(&wb->list_lock); + blk_finish_plug(&plug); +@@ -1765,7 +1758,7 @@ static long writeback_inodes_wb(struct b + * takes longer than a dirty_writeback_interval interval, then leave a + * one-second gap. + * +- * older_than_this takes precedence over nr_to_write. So we'll only write back ++ * dirtied_before takes precedence over nr_to_write. So we'll only write back + * all dirty pages if they are all attached to "old" mappings. + */ + static long wb_writeback(struct bdi_writeback *wb, +@@ -1773,14 +1766,11 @@ static long wb_writeback(struct bdi_writ + { + unsigned long wb_start = jiffies; + long nr_pages = work->nr_pages; +- unsigned long oldest_jif; ++ unsigned long dirtied_before = jiffies; + struct inode *inode; + long progress; + struct blk_plug plug; + +- oldest_jif = jiffies; +- work->older_than_this = &oldest_jif; +- + blk_start_plug(&plug); + spin_lock(&wb->list_lock); + for (;;) { +@@ -1814,14 +1804,14 @@ static long wb_writeback(struct bdi_writ + * safe. + */ + if (work->for_kupdate) { +- oldest_jif = jiffies - ++ dirtied_before = jiffies - + msecs_to_jiffies(dirty_expire_interval * 10); + } else if (work->for_background) +- oldest_jif = jiffies; ++ dirtied_before = jiffies; + + trace_writeback_start(wb, work); + if (list_empty(&wb->b_io)) +- queue_io(wb, work); ++ queue_io(wb, work, dirtied_before); + if (work->sb) + progress = writeback_sb_inodes(work->sb, wb, work); + else +--- a/include/trace/events/writeback.h ++++ b/include/trace/events/writeback.h +@@ -360,8 +360,9 @@ DEFINE_WBC_EVENT(wbc_writepage); + TRACE_EVENT(writeback_queue_io, + TP_PROTO(struct bdi_writeback *wb, + struct wb_writeback_work *work, ++ unsigned long dirtied_before, + int moved), +- TP_ARGS(wb, work, moved), ++ TP_ARGS(wb, work, dirtied_before, moved), + TP_STRUCT__entry( + __array(char, name, 32) + __field(unsigned long, older) +@@ -371,19 +372,17 @@ TRACE_EVENT(writeback_queue_io, + __field(unsigned int, cgroup_ino) + ), + TP_fast_assign( +- unsigned long *older_than_this = work->older_than_this; + strncpy(__entry->name, dev_name(wb->bdi->dev), 32); +- __entry->older = older_than_this ? *older_than_this : 0; +- __entry->age = older_than_this ? +- (jiffies - *older_than_this) * 1000 / HZ : -1; ++ __entry->older = dirtied_before; ++ __entry->age = (jiffies - dirtied_before) * 1000 / HZ; + __entry->moved = moved; + __entry->reason = work->reason; + __entry->cgroup_ino = __trace_wb_assign_cgroup(wb); + ), + TP_printk("bdi %s: older=%lu age=%ld enqueue=%d reason=%s cgroup_ino=%u", + __entry->name, +- __entry->older, /* older_than_this in jiffies */ +- __entry->age, /* older_than_this in relative milliseconds */ ++ __entry->older, /* dirtied_before in jiffies */ ++ __entry->age, /* dirtied_before in relative milliseconds */ + __entry->moved, + __print_symbolic(__entry->reason, WB_WORK_REASON), + __entry->cgroup_ino diff --git a/queue-4.9/writeback-protect-inode-i_io_list-with-inode-i_lock.patch b/queue-4.9/writeback-protect-inode-i_io_list-with-inode-i_lock.patch new file mode 100644 index 00000000000..2f5f0bbb331 --- /dev/null +++ b/queue-4.9/writeback-protect-inode-i_io_list-with-inode-i_lock.patch @@ -0,0 +1,107 @@ +From b35250c0816c7cf7d0a8de92f5fafb6a7508a708 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Wed, 10 Jun 2020 17:36:03 +0200 +Subject: writeback: Protect inode->i_io_list with inode->i_lock + +From: Jan Kara + +commit b35250c0816c7cf7d0a8de92f5fafb6a7508a708 upstream. + +Currently, operations on inode->i_io_list are protected by +wb->list_lock. In the following patches we'll need to maintain +consistency between inode->i_state and inode->i_io_list so change the +code so that inode->i_lock protects also all inode's i_io_list handling. + +Reviewed-by: Martijn Coenen +Reviewed-by: Christoph Hellwig +CC: stable@vger.kernel.org # Prerequisite for "writeback: Avoid skipping inode writeback" +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fs-writeback.c | 22 +++++++++++++++++----- + 1 file changed, 17 insertions(+), 5 deletions(-) + +--- a/fs/fs-writeback.c ++++ b/fs/fs-writeback.c +@@ -160,6 +160,7 @@ static void inode_io_list_del_locked(str + struct bdi_writeback *wb) + { + assert_spin_locked(&wb->list_lock); ++ assert_spin_locked(&inode->i_lock); + + list_del_init(&inode->i_io_list); + wb_io_lists_depopulated(wb); +@@ -1039,7 +1040,9 @@ void inode_io_list_del(struct inode *ino + struct bdi_writeback *wb; + + wb = inode_to_wb_and_lock_list(inode); ++ spin_lock(&inode->i_lock); + inode_io_list_del_locked(inode, wb); ++ spin_unlock(&inode->i_lock); + spin_unlock(&wb->list_lock); + } + +@@ -1088,8 +1091,10 @@ void sb_clear_inode_writeback(struct ino + * the case then the inode must have been redirtied while it was being written + * out and we don't reset its dirtied_when. + */ +-static void redirty_tail(struct inode *inode, struct bdi_writeback *wb) ++static void redirty_tail_locked(struct inode *inode, struct bdi_writeback *wb) + { ++ assert_spin_locked(&inode->i_lock); ++ + if (!list_empty(&wb->b_dirty)) { + struct inode *tail; + +@@ -1100,6 +1105,13 @@ static void redirty_tail(struct inode *i + inode_io_list_move_locked(inode, wb, &wb->b_dirty); + } + ++static void redirty_tail(struct inode *inode, struct bdi_writeback *wb) ++{ ++ spin_lock(&inode->i_lock); ++ redirty_tail_locked(inode, wb); ++ spin_unlock(&inode->i_lock); ++} ++ + /* + * requeue inode for re-scanning after bdi->b_io list is exhausted. + */ +@@ -1310,7 +1322,7 @@ static void requeue_inode(struct inode * + * writeback is not making progress due to locked + * buffers. Skip this inode for now. + */ +- redirty_tail(inode, wb); ++ redirty_tail_locked(inode, wb); + return; + } + +@@ -1330,7 +1342,7 @@ static void requeue_inode(struct inode * + * retrying writeback of the dirty page/inode + * that cannot be performed immediately. + */ +- redirty_tail(inode, wb); ++ redirty_tail_locked(inode, wb); + } + } else if (inode->i_state & I_DIRTY) { + /* +@@ -1338,7 +1350,7 @@ static void requeue_inode(struct inode * + * such as delayed allocation during submission or metadata + * updates after data IO completion. + */ +- redirty_tail(inode, wb); ++ redirty_tail_locked(inode, wb); + } else if (inode->i_state & I_DIRTY_TIME) { + inode->dirtied_when = jiffies; + inode_io_list_move_locked(inode, wb, &wb->b_dirty_time); +@@ -1585,8 +1597,8 @@ static long writeback_sb_inodes(struct s + */ + spin_lock(&inode->i_lock); + if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { ++ redirty_tail_locked(inode, wb); + spin_unlock(&inode->i_lock); +- redirty_tail(inode, wb); + continue; + } + if ((inode->i_state & I_SYNC) && wbc.sync_mode != WB_SYNC_ALL) { diff --git a/queue-4.9/xen-uses-irqdesc-irq_data_common-handler_data-to-store-a-per-interrupt-xen-data-pointer-which-contains-xen-specific-information.patch b/queue-4.9/xen-uses-irqdesc-irq_data_common-handler_data-to-store-a-per-interrupt-xen-data-pointer-which-contains-xen-specific-information.patch new file mode 100644 index 00000000000..f91da2a2839 --- /dev/null +++ b/queue-4.9/xen-uses-irqdesc-irq_data_common-handler_data-to-store-a-per-interrupt-xen-data-pointer-which-contains-xen-specific-information.patch @@ -0,0 +1,107 @@ +From c330fb1ddc0a922f044989492b7fcca77ee1db46 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 25 Aug 2020 17:22:58 +0200 +Subject: XEN uses irqdesc::irq_data_common::handler_data to store a per interrupt XEN data pointer which contains XEN specific information. + +From: Thomas Gleixner + +commit c330fb1ddc0a922f044989492b7fcca77ee1db46 upstream. + +handler data is meant for interrupt handlers and not for storing irq chip +specific information as some devices require handler data to store internal +per interrupt information, e.g. pinctrl/GPIO chained interrupt handlers. + +This obviously creates a conflict of interests and crashes the machine +because the XEN pointer is overwritten by the driver pointer. + +As the XEN data is not handler specific it should be stored in +irqdesc::irq_data::chip_data instead. + +A simple sed s/irq_[sg]et_handler_data/irq_[sg]et_chip_data/ cures that. + +Cc: stable@vger.kernel.org +Reported-by: Roman Shaposhnik +Signed-off-by: Thomas Gleixner +Tested-by: Roman Shaposhnik +Reviewed-by: Juergen Gross +Link: https://lore.kernel.org/r/87lfi2yckt.fsf@nanos.tec.linutronix.de +Signed-off-by: Juergen Gross +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/xen/events/events_base.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +--- a/drivers/xen/events/events_base.c ++++ b/drivers/xen/events/events_base.c +@@ -155,7 +155,7 @@ int get_evtchn_to_irq(unsigned evtchn) + /* Get info for IRQ */ + struct irq_info *info_for_irq(unsigned irq) + { +- return irq_get_handler_data(irq); ++ return irq_get_chip_data(irq); + } + + /* Constructors for packed IRQ information. */ +@@ -384,7 +384,7 @@ static void xen_irq_init(unsigned irq) + info->type = IRQT_UNBOUND; + info->refcnt = -1; + +- irq_set_handler_data(irq, info); ++ irq_set_chip_data(irq, info); + + list_add_tail(&info->list, &xen_irq_list_head); + } +@@ -433,14 +433,14 @@ static int __must_check xen_allocate_irq + + static void xen_free_irq(unsigned irq) + { +- struct irq_info *info = irq_get_handler_data(irq); ++ struct irq_info *info = irq_get_chip_data(irq); + + if (WARN_ON(!info)) + return; + + list_del(&info->list); + +- irq_set_handler_data(irq, NULL); ++ irq_set_chip_data(irq, NULL); + + WARN_ON(info->refcnt > 0); + +@@ -610,7 +610,7 @@ EXPORT_SYMBOL_GPL(xen_irq_from_gsi); + static void __unbind_from_irq(unsigned int irq) + { + int evtchn = evtchn_from_irq(irq); +- struct irq_info *info = irq_get_handler_data(irq); ++ struct irq_info *info = irq_get_chip_data(irq); + + if (info->refcnt > 0) { + info->refcnt--; +@@ -1114,7 +1114,7 @@ int bind_ipi_to_irqhandler(enum ipi_vect + + void unbind_from_irqhandler(unsigned int irq, void *dev_id) + { +- struct irq_info *info = irq_get_handler_data(irq); ++ struct irq_info *info = irq_get_chip_data(irq); + + if (WARN_ON(!info)) + return; +@@ -1148,7 +1148,7 @@ int evtchn_make_refcounted(unsigned int + if (irq == -1) + return -ENOENT; + +- info = irq_get_handler_data(irq); ++ info = irq_get_chip_data(irq); + + if (!info) + return -ENOENT; +@@ -1176,7 +1176,7 @@ int evtchn_get(unsigned int evtchn) + if (irq == -1) + goto done; + +- info = irq_get_handler_data(irq); ++ info = irq_get_chip_data(irq); + + if (!info) + goto done; diff --git a/queue-4.9/xhci-do-warm-reset-when-both-cas-and-xdev_resume-are-set.patch b/queue-4.9/xhci-do-warm-reset-when-both-cas-and-xdev_resume-are-set.patch new file mode 100644 index 00000000000..6ac26331cd8 --- /dev/null +++ b/queue-4.9/xhci-do-warm-reset-when-both-cas-and-xdev_resume-are-set.patch @@ -0,0 +1,69 @@ +From 904df64a5f4d5ebd670801d869ca0a6d6a6e8df6 Mon Sep 17 00:00:00 2001 +From: Kai-Heng Feng +Date: Fri, 21 Aug 2020 12:15:48 +0300 +Subject: xhci: Do warm-reset when both CAS and XDEV_RESUME are set + +From: Kai-Heng Feng + +commit 904df64a5f4d5ebd670801d869ca0a6d6a6e8df6 upstream. + +Sometimes re-plugging a USB device during system sleep renders the device +useless: +[ 173.418345] xhci_hcd 0000:00:14.0: Get port status 2-4 read: 0x14203e2, return 0x10262 +... +[ 176.496485] usb 2-4: Waited 2000ms for CONNECT +[ 176.496781] usb usb2-port4: status 0000.0262 after resume, -19 +[ 176.497103] usb 2-4: can't resume, status -19 +[ 176.497438] usb usb2-port4: logical disconnect + +Because PLS equals to XDEV_RESUME, xHCI driver reports U3 to usbcore, +despite of CAS bit is flagged. + +So proritize CAS over XDEV_RESUME to let usbcore handle warm-reset for +the port. + +Cc: stable +Signed-off-by: Kai-Heng Feng +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20200821091549.20556-3-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-hub.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +--- a/drivers/usb/host/xhci-hub.c ++++ b/drivers/usb/host/xhci-hub.c +@@ -623,15 +623,6 @@ static void xhci_hub_report_usb3_link_st + { + u32 pls = status_reg & PORT_PLS_MASK; + +- /* resume state is a xHCI internal state. +- * Do not report it to usb core, instead, pretend to be U3, +- * thus usb core knows it's not ready for transfer +- */ +- if (pls == XDEV_RESUME) { +- *status |= USB_SS_PORT_LS_U3; +- return; +- } +- + /* When the CAS bit is set then warm reset + * should be performed on port + */ +@@ -654,6 +645,16 @@ static void xhci_hub_report_usb3_link_st + pls |= USB_PORT_STAT_CONNECTION; + } else { + /* ++ * Resume state is an xHCI internal state. Do not report it to ++ * usb core, instead, pretend to be U3, thus usb core knows ++ * it's not ready for transfer. ++ */ ++ if (pls == XDEV_RESUME) { ++ *status |= USB_SS_PORT_LS_U3; ++ return; ++ } ++ ++ /* + * If CAS bit isn't set but the Port is already at + * Compliance Mode, fake a connection so the USB core + * notices the Compliance state and resets the port.