Contents of /trunk/kernel-alx-legacy/patches-4.9/0379-4.9.280-all-fixes.patch
Parent Directory | Revision Log
Revision 3681 -
(show annotations)
(download)
Mon Oct 24 14:07:57 2022 UTC (23 months ago) by niro
File size: 33043 byte(s)
Mon Oct 24 14:07:57 2022 UTC (23 months ago) by niro
File size: 33043 byte(s)
-linux-4.9.280
1 | diff --git a/Makefile b/Makefile |
2 | index b88bc8d14ca38..7cd5634469b10 100644 |
3 | --- a/Makefile |
4 | +++ b/Makefile |
5 | @@ -1,6 +1,6 @@ |
6 | VERSION = 4 |
7 | PATCHLEVEL = 9 |
8 | -SUBLEVEL = 279 |
9 | +SUBLEVEL = 280 |
10 | EXTRAVERSION = |
11 | NAME = Roaring Lionus |
12 | |
13 | diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c |
14 | index 46bf263c31531..d2477a502ce74 100644 |
15 | --- a/arch/alpha/kernel/smp.c |
16 | +++ b/arch/alpha/kernel/smp.c |
17 | @@ -584,7 +584,7 @@ void |
18 | smp_send_stop(void) |
19 | { |
20 | cpumask_t to_whom; |
21 | - cpumask_copy(&to_whom, cpu_possible_mask); |
22 | + cpumask_copy(&to_whom, cpu_online_mask); |
23 | cpumask_clear_cpu(smp_processor_id(), &to_whom); |
24 | #ifdef DEBUG_IPI_MSG |
25 | if (hard_smp_processor_id() != boot_cpu_id) |
26 | diff --git a/arch/mips/Makefile b/arch/mips/Makefile |
27 | index 25f3bfef9b390..af4eff7d22ecc 100644 |
28 | --- a/arch/mips/Makefile |
29 | +++ b/arch/mips/Makefile |
30 | @@ -286,7 +286,7 @@ LDFLAGS += -m $(ld-emul) |
31 | |
32 | ifdef CONFIG_MIPS |
33 | CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \ |
34 | - egrep -vw '__GNUC_(|MINOR_|PATCHLEVEL_)_' | \ |
35 | + egrep -vw '__GNUC_(MINOR_|PATCHLEVEL_)?_' | \ |
36 | sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/" -e 's/\$$/&&/g') |
37 | ifdef CONFIG_64BIT |
38 | CHECKFLAGS += -m64 |
39 | diff --git a/arch/mips/mti-malta/malta-platform.c b/arch/mips/mti-malta/malta-platform.c |
40 | index 516e1233d771c..0e51db7ac1725 100644 |
41 | --- a/arch/mips/mti-malta/malta-platform.c |
42 | +++ b/arch/mips/mti-malta/malta-platform.c |
43 | @@ -48,7 +48,8 @@ static struct plat_serial8250_port uart8250_data[] = { |
44 | .mapbase = 0x1f000900, /* The CBUS UART */ |
45 | .irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB2, |
46 | .uartclk = 3686400, /* Twice the usual clk! */ |
47 | - .iotype = UPIO_MEM32, |
48 | + .iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ? |
49 | + UPIO_MEM32BE : UPIO_MEM32, |
50 | .flags = CBUS_UART_FLAGS, |
51 | .regshift = 3, |
52 | }, |
53 | diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h |
54 | index c42c9d50c8ee8..8095c7169e8a1 100644 |
55 | --- a/arch/x86/events/perf_event.h |
56 | +++ b/arch/x86/events/perf_event.h |
57 | @@ -771,9 +771,10 @@ void x86_pmu_stop(struct perf_event *event, int flags); |
58 | |
59 | static inline void x86_pmu_disable_event(struct perf_event *event) |
60 | { |
61 | + u64 disable_mask = __this_cpu_read(cpu_hw_events.perf_ctr_virt_mask); |
62 | struct hw_perf_event *hwc = &event->hw; |
63 | |
64 | - wrmsrl(hwc->config_base, hwc->config); |
65 | + wrmsrl(hwc->config_base, hwc->config & ~disable_mask); |
66 | } |
67 | |
68 | void x86_pmu_enable_event(struct perf_event *event); |
69 | diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c |
70 | index c583c638e4681..328a447ce9723 100644 |
71 | --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c |
72 | +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c |
73 | @@ -50,7 +50,16 @@ static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req) |
74 | } else { |
75 | /* read */ |
76 | requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); |
77 | - pipe = usb_rcvctrlpipe(d->udev, 0); |
78 | + |
79 | + /* |
80 | + * Zero-length transfers must use usb_sndctrlpipe() and |
81 | + * rtl28xxu_identify_state() uses a zero-length i2c read |
82 | + * command to determine the chip type. |
83 | + */ |
84 | + if (req->size) |
85 | + pipe = usb_rcvctrlpipe(d->udev, 0); |
86 | + else |
87 | + pipe = usb_sndctrlpipe(d->udev, 0); |
88 | } |
89 | |
90 | ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value, |
91 | diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c |
92 | index b1a4d4e2341ba..3ac9f7260e723 100644 |
93 | --- a/drivers/media/v4l2-core/videobuf2-core.c |
94 | +++ b/drivers/media/v4l2-core/videobuf2-core.c |
95 | @@ -1370,6 +1370,7 @@ static int vb2_start_streaming(struct vb2_queue *q) |
96 | int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb) |
97 | { |
98 | struct vb2_buffer *vb; |
99 | + enum vb2_buffer_state orig_state; |
100 | int ret; |
101 | |
102 | if (q->error) { |
103 | @@ -1399,6 +1400,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb) |
104 | * Add to the queued buffers list, a buffer will stay on it until |
105 | * dequeued in dqbuf. |
106 | */ |
107 | + orig_state = vb->state; |
108 | list_add_tail(&vb->queued_entry, &q->queued_list); |
109 | q->queued_count++; |
110 | q->waiting_for_buffers = false; |
111 | @@ -1429,8 +1431,17 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb) |
112 | if (q->streaming && !q->start_streaming_called && |
113 | q->queued_count >= q->min_buffers_needed) { |
114 | ret = vb2_start_streaming(q); |
115 | - if (ret) |
116 | + if (ret) { |
117 | + /* |
118 | + * Since vb2_core_qbuf will return with an error, |
119 | + * we should return it to state DEQUEUED since |
120 | + * the error indicates that the buffer wasn't queued. |
121 | + */ |
122 | + list_del(&vb->queued_entry); |
123 | + q->queued_count--; |
124 | + vb->state = orig_state; |
125 | return ret; |
126 | + } |
127 | } |
128 | |
129 | dprintk(1, "qbuf of buffer %d succeeded\n", vb->index); |
130 | diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c |
131 | index 46a7dcf2ff4a3..9d7f491931cef 100644 |
132 | --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c |
133 | +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c |
134 | @@ -2672,7 +2672,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) |
135 | } |
136 | |
137 | /* Allocated memory for FW statistics */ |
138 | - if (bnx2x_alloc_fw_stats_mem(bp)) |
139 | + rc = bnx2x_alloc_fw_stats_mem(bp); |
140 | + if (rc) |
141 | LOAD_ERROR_EXIT(bp, load_error0); |
142 | |
143 | /* request pf to initialize status blocks */ |
144 | diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c |
145 | index 9b3ea0406e0d5..5fc40f025d214 100644 |
146 | --- a/drivers/net/ethernet/freescale/fec_main.c |
147 | +++ b/drivers/net/ethernet/freescale/fec_main.c |
148 | @@ -3546,13 +3546,13 @@ fec_drv_remove(struct platform_device *pdev) |
149 | if (of_phy_is_fixed_link(np)) |
150 | of_phy_deregister_fixed_link(np); |
151 | of_node_put(fep->phy_node); |
152 | - free_netdev(ndev); |
153 | |
154 | clk_disable_unprepare(fep->clk_ahb); |
155 | clk_disable_unprepare(fep->clk_ipg); |
156 | pm_runtime_put_noidle(&pdev->dev); |
157 | pm_runtime_disable(&pdev->dev); |
158 | |
159 | + free_netdev(ndev); |
160 | return 0; |
161 | } |
162 | |
163 | diff --git a/drivers/net/ethernet/natsemi/natsemi.c b/drivers/net/ethernet/natsemi/natsemi.c |
164 | index ed89029ff75be..c0e128e17321f 100644 |
165 | --- a/drivers/net/ethernet/natsemi/natsemi.c |
166 | +++ b/drivers/net/ethernet/natsemi/natsemi.c |
167 | @@ -817,7 +817,7 @@ static int natsemi_probe1(struct pci_dev *pdev, const struct pci_device_id *ent) |
168 | printk(version); |
169 | #endif |
170 | |
171 | - i = pci_enable_device(pdev); |
172 | + i = pcim_enable_device(pdev); |
173 | if (i) return i; |
174 | |
175 | /* natsemi has a non-standard PM control register |
176 | @@ -850,7 +850,7 @@ static int natsemi_probe1(struct pci_dev *pdev, const struct pci_device_id *ent) |
177 | ioaddr = ioremap(iostart, iosize); |
178 | if (!ioaddr) { |
179 | i = -ENOMEM; |
180 | - goto err_ioremap; |
181 | + goto err_pci_request_regions; |
182 | } |
183 | |
184 | /* Work around the dropped serial bit. */ |
185 | @@ -968,9 +968,6 @@ static int natsemi_probe1(struct pci_dev *pdev, const struct pci_device_id *ent) |
186 | err_register_netdev: |
187 | iounmap(ioaddr); |
188 | |
189 | - err_ioremap: |
190 | - pci_release_regions(pdev); |
191 | - |
192 | err_pci_request_regions: |
193 | free_netdev(dev); |
194 | return i; |
195 | @@ -3228,7 +3225,6 @@ static void natsemi_remove1(struct pci_dev *pdev) |
196 | |
197 | NATSEMI_REMOVE_FILE(pdev, dspcfg_workaround); |
198 | unregister_netdev (dev); |
199 | - pci_release_regions (pdev); |
200 | iounmap(ioaddr); |
201 | free_netdev (dev); |
202 | } |
203 | diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c |
204 | index e0993eba5df3f..c6950e5808836 100644 |
205 | --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c |
206 | +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c |
207 | @@ -3539,13 +3539,13 @@ static void vxge_device_unregister(struct __vxge_hw_device *hldev) |
208 | |
209 | kfree(vdev->vpaths); |
210 | |
211 | - /* we are safe to free it now */ |
212 | - free_netdev(dev); |
213 | - |
214 | vxge_debug_init(vdev->level_trace, "%s: ethernet device unregistered", |
215 | buf); |
216 | vxge_debug_entryexit(vdev->level_trace, "%s: %s:%d Exiting...", buf, |
217 | __func__, __LINE__); |
218 | + |
219 | + /* we are safe to free it now */ |
220 | + free_netdev(dev); |
221 | } |
222 | |
223 | /* |
224 | diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c |
225 | index 192950a112c93..cb9d43c871c4c 100644 |
226 | --- a/drivers/net/ethernet/qlogic/qla3xxx.c |
227 | +++ b/drivers/net/ethernet/qlogic/qla3xxx.c |
228 | @@ -155,7 +155,7 @@ static int ql_wait_for_drvr_lock(struct ql3_adapter *qdev) |
229 | "driver lock acquired\n"); |
230 | return 1; |
231 | } |
232 | - ssleep(1); |
233 | + mdelay(1000); |
234 | } while (++i < 10); |
235 | |
236 | netdev_err(qdev->ndev, "Timed out waiting for driver lock...\n"); |
237 | @@ -3287,7 +3287,7 @@ static int ql_adapter_reset(struct ql3_adapter *qdev) |
238 | if ((value & ISP_CONTROL_SR) == 0) |
239 | break; |
240 | |
241 | - ssleep(1); |
242 | + mdelay(1000); |
243 | } while ((--max_wait_time)); |
244 | |
245 | /* |
246 | @@ -3323,7 +3323,7 @@ static int ql_adapter_reset(struct ql3_adapter *qdev) |
247 | ispControlStatus); |
248 | if ((value & ISP_CONTROL_FSR) == 0) |
249 | break; |
250 | - ssleep(1); |
251 | + mdelay(1000); |
252 | } while ((--max_wait_time)); |
253 | } |
254 | if (max_wait_time == 0) |
255 | diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c |
256 | index 034b36442ee75..df3b3384984ce 100644 |
257 | --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c |
258 | +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c |
259 | @@ -1179,9 +1179,8 @@ static int xemaclite_of_probe(struct platform_device *ofdev) |
260 | } |
261 | |
262 | dev_info(dev, |
263 | - "Xilinx EmacLite at 0x%08X mapped to 0x%08X, irq=%d\n", |
264 | - (unsigned int __force)ndev->mem_start, |
265 | - (unsigned int __force)lp->base_addr, ndev->irq); |
266 | + "Xilinx EmacLite at 0x%08X mapped to 0x%p, irq=%d\n", |
267 | + (unsigned int __force)ndev->mem_start, lp->base_addr, ndev->irq); |
268 | return 0; |
269 | |
270 | error: |
271 | diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c |
272 | index 801bab5968d04..5ba472691546b 100644 |
273 | --- a/drivers/net/ppp/ppp_generic.c |
274 | +++ b/drivers/net/ppp/ppp_generic.c |
275 | @@ -285,7 +285,7 @@ static struct channel *ppp_find_channel(struct ppp_net *pn, int unit); |
276 | static int ppp_connect_channel(struct channel *pch, int unit); |
277 | static int ppp_disconnect_channel(struct channel *pch); |
278 | static void ppp_destroy_channel(struct channel *pch); |
279 | -static int unit_get(struct idr *p, void *ptr); |
280 | +static int unit_get(struct idr *p, void *ptr, int min); |
281 | static int unit_set(struct idr *p, void *ptr, int n); |
282 | static void unit_put(struct idr *p, int n); |
283 | static void *unit_find(struct idr *p, int n); |
284 | @@ -976,9 +976,20 @@ static int ppp_unit_register(struct ppp *ppp, int unit, bool ifname_is_set) |
285 | mutex_lock(&pn->all_ppp_mutex); |
286 | |
287 | if (unit < 0) { |
288 | - ret = unit_get(&pn->units_idr, ppp); |
289 | + ret = unit_get(&pn->units_idr, ppp, 0); |
290 | if (ret < 0) |
291 | goto err; |
292 | + if (!ifname_is_set) { |
293 | + while (1) { |
294 | + snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ret); |
295 | + if (!__dev_get_by_name(ppp->ppp_net, ppp->dev->name)) |
296 | + break; |
297 | + unit_put(&pn->units_idr, ret); |
298 | + ret = unit_get(&pn->units_idr, ppp, ret + 1); |
299 | + if (ret < 0) |
300 | + goto err; |
301 | + } |
302 | + } |
303 | } else { |
304 | /* Caller asked for a specific unit number. Fail with -EEXIST |
305 | * if unavailable. For backward compatibility, return -EEXIST |
306 | @@ -3265,9 +3276,9 @@ static int unit_set(struct idr *p, void *ptr, int n) |
307 | } |
308 | |
309 | /* get new free unit number and associate pointer with it */ |
310 | -static int unit_get(struct idr *p, void *ptr) |
311 | +static int unit_get(struct idr *p, void *ptr, int min) |
312 | { |
313 | - return idr_alloc(p, ptr, 0, 0, GFP_KERNEL); |
314 | + return idr_alloc(p, ptr, min, 0, GFP_KERNEL); |
315 | } |
316 | |
317 | /* put unit number back to a pool */ |
318 | diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c |
319 | index 5fe9f1273fe20..6cfc6faf97471 100644 |
320 | --- a/drivers/net/usb/pegasus.c |
321 | +++ b/drivers/net/usb/pegasus.c |
322 | @@ -755,12 +755,16 @@ static inline void disable_net_traffic(pegasus_t *pegasus) |
323 | set_registers(pegasus, EthCtrl0, sizeof(tmp), &tmp); |
324 | } |
325 | |
326 | -static inline void get_interrupt_interval(pegasus_t *pegasus) |
327 | +static inline int get_interrupt_interval(pegasus_t *pegasus) |
328 | { |
329 | u16 data; |
330 | u8 interval; |
331 | + int ret; |
332 | + |
333 | + ret = read_eprom_word(pegasus, 4, &data); |
334 | + if (ret < 0) |
335 | + return ret; |
336 | |
337 | - read_eprom_word(pegasus, 4, &data); |
338 | interval = data >> 8; |
339 | if (pegasus->usb->speed != USB_SPEED_HIGH) { |
340 | if (interval < 0x80) { |
341 | @@ -775,6 +779,8 @@ static inline void get_interrupt_interval(pegasus_t *pegasus) |
342 | } |
343 | } |
344 | pegasus->intr_interval = interval; |
345 | + |
346 | + return 0; |
347 | } |
348 | |
349 | static void set_carrier(struct net_device *net) |
350 | @@ -1191,7 +1197,9 @@ static int pegasus_probe(struct usb_interface *intf, |
351 | | NETIF_MSG_PROBE | NETIF_MSG_LINK); |
352 | |
353 | pegasus->features = usb_dev_id[dev_index].private; |
354 | - get_interrupt_interval(pegasus); |
355 | + res = get_interrupt_interval(pegasus); |
356 | + if (res) |
357 | + goto out2; |
358 | if (reset_mac(pegasus)) { |
359 | dev_err(&intf->dev, "can't reset MAC\n"); |
360 | res = -EIO; |
361 | diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c |
362 | index aae7e6df99cd3..ba13e3c3d6b87 100644 |
363 | --- a/drivers/pcmcia/i82092.c |
364 | +++ b/drivers/pcmcia/i82092.c |
365 | @@ -105,6 +105,7 @@ static int i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *i |
366 | for (i = 0;i<socket_count;i++) { |
367 | sockets[i].card_state = 1; /* 1 = present but empty */ |
368 | sockets[i].io_base = pci_resource_start(dev, 0); |
369 | + sockets[i].dev = dev; |
370 | sockets[i].socket.features |= SS_CAP_PCCARD; |
371 | sockets[i].socket.map_size = 0x1000; |
372 | sockets[i].socket.irq_mask = 0; |
373 | diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c |
374 | index 5e51a39a0c27e..9b63e46edffcc 100644 |
375 | --- a/drivers/scsi/sr.c |
376 | +++ b/drivers/scsi/sr.c |
377 | @@ -217,7 +217,7 @@ static unsigned int sr_get_events(struct scsi_device *sdev) |
378 | else if (med->media_event_code == 2) |
379 | return DISK_EVENT_MEDIA_CHANGE; |
380 | else if (med->media_event_code == 3) |
381 | - return DISK_EVENT_EJECT_REQUEST; |
382 | + return DISK_EVENT_MEDIA_CHANGE; |
383 | return 0; |
384 | } |
385 | |
386 | diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c |
387 | index 827a641ac336e..611bc05565719 100644 |
388 | --- a/drivers/tty/serial/8250/8250_port.c |
389 | +++ b/drivers/tty/serial/8250/8250_port.c |
390 | @@ -277,7 +277,11 @@ static const struct serial8250_config uart_config[] = { |
391 | /* Uart divisor latch read */ |
392 | static int default_serial_dl_read(struct uart_8250_port *up) |
393 | { |
394 | - return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; |
395 | + /* Assign these in pieces to truncate any bits above 7. */ |
396 | + unsigned char dll = serial_in(up, UART_DLL); |
397 | + unsigned char dlm = serial_in(up, UART_DLM); |
398 | + |
399 | + return dll | dlm << 8; |
400 | } |
401 | |
402 | /* Uart divisor latch write */ |
403 | @@ -1262,9 +1266,11 @@ static void autoconfig(struct uart_8250_port *up) |
404 | serial_out(up, UART_LCR, 0); |
405 | |
406 | serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); |
407 | - scratch = serial_in(up, UART_IIR) >> 6; |
408 | |
409 | - switch (scratch) { |
410 | + /* Assign this as it is to truncate any bits above 7. */ |
411 | + scratch = serial_in(up, UART_IIR); |
412 | + |
413 | + switch (scratch >> 6) { |
414 | case 0: |
415 | autoconfig_8250(up); |
416 | break; |
417 | diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c |
418 | index a391b50fb32f1..c310c6d4d150a 100644 |
419 | --- a/drivers/usb/class/usbtmc.c |
420 | +++ b/drivers/usb/class/usbtmc.c |
421 | @@ -1342,16 +1342,10 @@ static void usbtmc_interrupt(struct urb *urb) |
422 | case -EOVERFLOW: |
423 | dev_err(dev, "overflow with length %d, actual length is %d\n", |
424 | data->iin_wMaxPacketSize, urb->actual_length); |
425 | - case -ECONNRESET: |
426 | - case -ENOENT: |
427 | - case -ESHUTDOWN: |
428 | - case -EILSEQ: |
429 | - case -ETIME: |
430 | + default: |
431 | /* urb terminated, clean up */ |
432 | dev_dbg(dev, "urb terminated, status: %d\n", status); |
433 | return; |
434 | - default: |
435 | - dev_err(dev, "unknown status received: %d\n", status); |
436 | } |
437 | exit: |
438 | rv = usb_submit_urb(urb, GFP_ATOMIC); |
439 | diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c |
440 | index 2f537bbdda093..362cca983e6e4 100644 |
441 | --- a/drivers/usb/common/usb-otg-fsm.c |
442 | +++ b/drivers/usb/common/usb-otg-fsm.c |
443 | @@ -199,7 +199,11 @@ static void otg_start_hnp_polling(struct otg_fsm *fsm) |
444 | if (!fsm->host_req_flag) |
445 | return; |
446 | |
447 | - INIT_DELAYED_WORK(&fsm->hnp_polling_work, otg_hnp_polling_work); |
448 | + if (!fsm->hnp_work_inited) { |
449 | + INIT_DELAYED_WORK(&fsm->hnp_polling_work, otg_hnp_polling_work); |
450 | + fsm->hnp_work_inited = true; |
451 | + } |
452 | + |
453 | schedule_delayed_work(&fsm->hnp_polling_work, |
454 | msecs_to_jiffies(T_HOST_REQ_POLL)); |
455 | } |
456 | diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c |
457 | index 08b3f8c806016..a31015a95fd64 100644 |
458 | --- a/drivers/usb/host/ehci-pci.c |
459 | +++ b/drivers/usb/host/ehci-pci.c |
460 | @@ -312,6 +312,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd) |
461 | if (pdev->vendor == PCI_VENDOR_ID_STMICRO |
462 | && pdev->device == PCI_DEVICE_ID_STMICRO_USB_HOST) |
463 | ; /* ConneXT has no sbrn register */ |
464 | + else if (pdev->vendor == PCI_VENDOR_ID_HUAWEI |
465 | + && pdev->device == 0xa239) |
466 | + ; /* HUAWEI Kunpeng920 USB EHCI has no sbrn register */ |
467 | else |
468 | pci_read_config_byte(pdev, 0x60, &ehci->sbrn); |
469 | |
470 | diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c |
471 | index c6ff79360302f..2e92c6fef683f 100644 |
472 | --- a/drivers/usb/serial/ch341.c |
473 | +++ b/drivers/usb/serial/ch341.c |
474 | @@ -585,6 +585,7 @@ static struct usb_serial_driver ch341_device = { |
475 | .owner = THIS_MODULE, |
476 | .name = "ch341-uart", |
477 | }, |
478 | + .bulk_in_size = 512, |
479 | .id_table = id_table, |
480 | .num_ports = 1, |
481 | .open = ch341_open, |
482 | diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c |
483 | index 8f4bd9fa82449..fe6b32c2ff1cb 100644 |
484 | --- a/drivers/usb/serial/ftdi_sio.c |
485 | +++ b/drivers/usb/serial/ftdi_sio.c |
486 | @@ -214,6 +214,7 @@ static const struct usb_device_id id_table_combined[] = { |
487 | { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, |
488 | { USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) }, |
489 | { USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) }, |
490 | + { USB_DEVICE(FTDI_VID, FTDI_AUTO_M3_OP_COM_V2_PID) }, |
491 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) }, |
492 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) }, |
493 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) }, |
494 | diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h |
495 | index 54ded2bc9eb6c..3b7cea8df446c 100644 |
496 | --- a/drivers/usb/serial/ftdi_sio_ids.h |
497 | +++ b/drivers/usb/serial/ftdi_sio_ids.h |
498 | @@ -158,6 +158,9 @@ |
499 | /* Vardaan Enterprises Serial Interface VEUSB422R3 */ |
500 | #define FTDI_VARDAAN_PID 0xF070 |
501 | |
502 | +/* Auto-M3 Ltd. - OP-COM USB V2 - OBD interface Adapter */ |
503 | +#define FTDI_AUTO_M3_OP_COM_V2_PID 0x4f50 |
504 | + |
505 | /* |
506 | * Xsens Technologies BV products (http://www.xsens.com). |
507 | */ |
508 | diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c |
509 | index b9017e85cc1ab..b3336a7c09e0b 100644 |
510 | --- a/drivers/usb/serial/option.c |
511 | +++ b/drivers/usb/serial/option.c |
512 | @@ -1185,6 +1185,8 @@ static const struct usb_device_id option_ids[] = { |
513 | .driver_info = NCTRL(2) | RSVD(3) }, |
514 | { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1055, 0xff), /* Telit FN980 (PCIe) */ |
515 | .driver_info = NCTRL(0) | RSVD(1) }, |
516 | + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1056, 0xff), /* Telit FD980 */ |
517 | + .driver_info = NCTRL(2) | RSVD(3) }, |
518 | { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910), |
519 | .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) }, |
520 | { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), |
521 | diff --git a/fs/namespace.c b/fs/namespace.c |
522 | index 3b20c7ff8cc3c..9f2390c89b63b 100644 |
523 | --- a/fs/namespace.c |
524 | +++ b/fs/namespace.c |
525 | @@ -1853,6 +1853,20 @@ void drop_collected_mounts(struct vfsmount *mnt) |
526 | namespace_unlock(); |
527 | } |
528 | |
529 | +static bool has_locked_children(struct mount *mnt, struct dentry *dentry) |
530 | +{ |
531 | + struct mount *child; |
532 | + |
533 | + list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { |
534 | + if (!is_subdir(child->mnt_mountpoint, dentry)) |
535 | + continue; |
536 | + |
537 | + if (child->mnt.mnt_flags & MNT_LOCKED) |
538 | + return true; |
539 | + } |
540 | + return false; |
541 | +} |
542 | + |
543 | /** |
544 | * clone_private_mount - create a private clone of a path |
545 | * |
546 | @@ -1867,16 +1881,27 @@ struct vfsmount *clone_private_mount(struct path *path) |
547 | struct mount *old_mnt = real_mount(path->mnt); |
548 | struct mount *new_mnt; |
549 | |
550 | + down_read(&namespace_sem); |
551 | if (IS_MNT_UNBINDABLE(old_mnt)) |
552 | - return ERR_PTR(-EINVAL); |
553 | + goto invalid; |
554 | + |
555 | + if (!check_mnt(old_mnt)) |
556 | + goto invalid; |
557 | + |
558 | + if (has_locked_children(old_mnt, path->dentry)) |
559 | + goto invalid; |
560 | |
561 | - down_read(&namespace_sem); |
562 | new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE); |
563 | up_read(&namespace_sem); |
564 | + |
565 | if (IS_ERR(new_mnt)) |
566 | return ERR_CAST(new_mnt); |
567 | |
568 | return &new_mnt->mnt; |
569 | + |
570 | +invalid: |
571 | + up_read(&namespace_sem); |
572 | + return ERR_PTR(-EINVAL); |
573 | } |
574 | EXPORT_SYMBOL_GPL(clone_private_mount); |
575 | |
576 | @@ -2192,19 +2217,6 @@ static int do_change_type(struct path *path, int flag) |
577 | return err; |
578 | } |
579 | |
580 | -static bool has_locked_children(struct mount *mnt, struct dentry *dentry) |
581 | -{ |
582 | - struct mount *child; |
583 | - list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { |
584 | - if (!is_subdir(child->mnt_mountpoint, dentry)) |
585 | - continue; |
586 | - |
587 | - if (child->mnt.mnt_flags & MNT_LOCKED) |
588 | - return true; |
589 | - } |
590 | - return false; |
591 | -} |
592 | - |
593 | /* |
594 | * do loopback mount. |
595 | */ |
596 | diff --git a/fs/pipe.c b/fs/pipe.c |
597 | index 347c6dc888c8f..6375e625a2635 100644 |
598 | --- a/fs/pipe.c |
599 | +++ b/fs/pipe.c |
600 | @@ -28,6 +28,21 @@ |
601 | |
602 | #include "internal.h" |
603 | |
604 | +/* |
605 | + * New pipe buffers will be restricted to this size while the user is exceeding |
606 | + * their pipe buffer quota. The general pipe use case needs at least two |
607 | + * buffers: one for data yet to be read, and one for new data. If this is less |
608 | + * than two, then a write to a non-empty pipe may block even if the pipe is not |
609 | + * full. This can occur with GNU make jobserver or similar uses of pipes as |
610 | + * semaphores: multiple processes may be waiting to write tokens back to the |
611 | + * pipe before reading tokens: https://lore.kernel.org/lkml/1628086770.5rn8p04n6j.none@localhost/. |
612 | + * |
613 | + * Users can reduce their pipe buffers with F_SETPIPE_SZ below this at their |
614 | + * own risk, namely: pipe writes to non-full pipes may block until the pipe is |
615 | + * emptied. |
616 | + */ |
617 | +#define PIPE_MIN_DEF_BUFFERS 2 |
618 | + |
619 | /* |
620 | * The max size that a non-root user is allowed to grow the pipe. Can |
621 | * be set by root in /proc/sys/fs/pipe-max-size |
622 | @@ -653,8 +668,8 @@ struct pipe_inode_info *alloc_pipe_info(void) |
623 | user_bufs = account_pipe_buffers(user, 0, pipe_bufs); |
624 | |
625 | if (too_many_pipe_buffers_soft(user_bufs) && is_unprivileged_user()) { |
626 | - user_bufs = account_pipe_buffers(user, pipe_bufs, 1); |
627 | - pipe_bufs = 1; |
628 | + user_bufs = account_pipe_buffers(user, pipe_bufs, PIPE_MIN_DEF_BUFFERS); |
629 | + pipe_bufs = PIPE_MIN_DEF_BUFFERS; |
630 | } |
631 | |
632 | if (too_many_pipe_buffers_hard(user_bufs) && is_unprivileged_user()) |
633 | diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c |
634 | index 25b2aed9af0b3..f2f7055303ca5 100644 |
635 | --- a/fs/reiserfs/stree.c |
636 | +++ b/fs/reiserfs/stree.c |
637 | @@ -386,6 +386,24 @@ void pathrelse(struct treepath *search_path) |
638 | search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET; |
639 | } |
640 | |
641 | +static int has_valid_deh_location(struct buffer_head *bh, struct item_head *ih) |
642 | +{ |
643 | + struct reiserfs_de_head *deh; |
644 | + int i; |
645 | + |
646 | + deh = B_I_DEH(bh, ih); |
647 | + for (i = 0; i < ih_entry_count(ih); i++) { |
648 | + if (deh_location(&deh[i]) > ih_item_len(ih)) { |
649 | + reiserfs_warning(NULL, "reiserfs-5094", |
650 | + "directory entry location seems wrong %h", |
651 | + &deh[i]); |
652 | + return 0; |
653 | + } |
654 | + } |
655 | + |
656 | + return 1; |
657 | +} |
658 | + |
659 | static int is_leaf(char *buf, int blocksize, struct buffer_head *bh) |
660 | { |
661 | struct block_head *blkh; |
662 | @@ -453,11 +471,14 @@ static int is_leaf(char *buf, int blocksize, struct buffer_head *bh) |
663 | "(second one): %h", ih); |
664 | return 0; |
665 | } |
666 | - if (is_direntry_le_ih(ih) && (ih_item_len(ih) < (ih_entry_count(ih) * IH_SIZE))) { |
667 | - reiserfs_warning(NULL, "reiserfs-5093", |
668 | - "item entry count seems wrong %h", |
669 | - ih); |
670 | - return 0; |
671 | + if (is_direntry_le_ih(ih)) { |
672 | + if (ih_item_len(ih) < (ih_entry_count(ih) * IH_SIZE)) { |
673 | + reiserfs_warning(NULL, "reiserfs-5093", |
674 | + "item entry count seems wrong %h", |
675 | + ih); |
676 | + return 0; |
677 | + } |
678 | + return has_valid_deh_location(bh, ih); |
679 | } |
680 | prev_location = ih_location(ih); |
681 | } |
682 | diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c |
683 | index c533d8715a6ca..0d324c07762a3 100644 |
684 | --- a/fs/reiserfs/super.c |
685 | +++ b/fs/reiserfs/super.c |
686 | @@ -2059,6 +2059,14 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) |
687 | unlock_new_inode(root_inode); |
688 | } |
689 | |
690 | + if (!S_ISDIR(root_inode->i_mode) || !inode_get_bytes(root_inode) || |
691 | + !root_inode->i_size) { |
692 | + SWARN(silent, s, "", "corrupt root inode, run fsck"); |
693 | + iput(root_inode); |
694 | + errval = -EUCLEAN; |
695 | + goto error; |
696 | + } |
697 | + |
698 | s->s_root = d_make_root(root_inode); |
699 | if (!s->s_root) |
700 | goto error; |
701 | diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h |
702 | index 7a0350535cb10..603b298dc747d 100644 |
703 | --- a/include/linux/usb/otg-fsm.h |
704 | +++ b/include/linux/usb/otg-fsm.h |
705 | @@ -210,6 +210,7 @@ struct otg_fsm { |
706 | struct mutex lock; |
707 | u8 *host_req_flag; |
708 | struct delayed_work hnp_polling_work; |
709 | + bool hnp_work_inited; |
710 | bool state_changed; |
711 | }; |
712 | |
713 | diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h |
714 | index 33db6c6d3fba8..819796fb9d46f 100644 |
715 | --- a/include/net/bluetooth/hci_core.h |
716 | +++ b/include/net/bluetooth/hci_core.h |
717 | @@ -1028,6 +1028,7 @@ struct hci_dev *hci_alloc_dev(void); |
718 | void hci_free_dev(struct hci_dev *hdev); |
719 | int hci_register_dev(struct hci_dev *hdev); |
720 | void hci_unregister_dev(struct hci_dev *hdev); |
721 | +void hci_cleanup_dev(struct hci_dev *hdev); |
722 | int hci_suspend_dev(struct hci_dev *hdev); |
723 | int hci_resume_dev(struct hci_dev *hdev); |
724 | int hci_reset_dev(struct hci_dev *hdev); |
725 | diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c |
726 | index 839c534bdcdb9..8517da7f282ed 100644 |
727 | --- a/net/bluetooth/hci_core.c |
728 | +++ b/net/bluetooth/hci_core.c |
729 | @@ -3146,14 +3146,10 @@ EXPORT_SYMBOL(hci_register_dev); |
730 | /* Unregister HCI device */ |
731 | void hci_unregister_dev(struct hci_dev *hdev) |
732 | { |
733 | - int id; |
734 | - |
735 | BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); |
736 | |
737 | hci_dev_set_flag(hdev, HCI_UNREGISTER); |
738 | |
739 | - id = hdev->id; |
740 | - |
741 | write_lock(&hci_dev_list_lock); |
742 | list_del(&hdev->list); |
743 | write_unlock(&hci_dev_list_lock); |
744 | @@ -3182,7 +3178,14 @@ void hci_unregister_dev(struct hci_dev *hdev) |
745 | } |
746 | |
747 | device_del(&hdev->dev); |
748 | + /* Actual cleanup is deferred until hci_cleanup_dev(). */ |
749 | + hci_dev_put(hdev); |
750 | +} |
751 | +EXPORT_SYMBOL(hci_unregister_dev); |
752 | |
753 | +/* Cleanup HCI device */ |
754 | +void hci_cleanup_dev(struct hci_dev *hdev) |
755 | +{ |
756 | debugfs_remove_recursive(hdev->debugfs); |
757 | kfree_const(hdev->hw_info); |
758 | kfree_const(hdev->fw_info); |
759 | @@ -3204,11 +3207,8 @@ void hci_unregister_dev(struct hci_dev *hdev) |
760 | hci_discovery_filter_clear(hdev); |
761 | hci_dev_unlock(hdev); |
762 | |
763 | - hci_dev_put(hdev); |
764 | - |
765 | - ida_simple_remove(&hci_index_ida, id); |
766 | + ida_simple_remove(&hci_index_ida, hdev->id); |
767 | } |
768 | -EXPORT_SYMBOL(hci_unregister_dev); |
769 | |
770 | /* Suspend HCI device */ |
771 | int hci_suspend_dev(struct hci_dev *hdev) |
772 | diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c |
773 | index 35f5585188de7..d30163eb1643c 100644 |
774 | --- a/net/bluetooth/hci_sock.c |
775 | +++ b/net/bluetooth/hci_sock.c |
776 | @@ -59,6 +59,17 @@ struct hci_pinfo { |
777 | char comm[TASK_COMM_LEN]; |
778 | }; |
779 | |
780 | +static struct hci_dev *hci_hdev_from_sock(struct sock *sk) |
781 | +{ |
782 | + struct hci_dev *hdev = hci_pi(sk)->hdev; |
783 | + |
784 | + if (!hdev) |
785 | + return ERR_PTR(-EBADFD); |
786 | + if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) |
787 | + return ERR_PTR(-EPIPE); |
788 | + return hdev; |
789 | +} |
790 | + |
791 | void hci_sock_set_flag(struct sock *sk, int nr) |
792 | { |
793 | set_bit(nr, &hci_pi(sk)->flags); |
794 | @@ -747,19 +758,13 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event) |
795 | if (event == HCI_DEV_UNREG) { |
796 | struct sock *sk; |
797 | |
798 | - /* Detach sockets from device */ |
799 | + /* Wake up sockets using this dead device */ |
800 | read_lock(&hci_sk_list.lock); |
801 | sk_for_each(sk, &hci_sk_list.head) { |
802 | - lock_sock(sk); |
803 | if (hci_pi(sk)->hdev == hdev) { |
804 | - hci_pi(sk)->hdev = NULL; |
805 | sk->sk_err = EPIPE; |
806 | - sk->sk_state = BT_OPEN; |
807 | sk->sk_state_change(sk); |
808 | - |
809 | - hci_dev_put(hdev); |
810 | } |
811 | - release_sock(sk); |
812 | } |
813 | read_unlock(&hci_sk_list.lock); |
814 | } |
815 | @@ -918,10 +923,10 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) |
816 | static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, |
817 | unsigned long arg) |
818 | { |
819 | - struct hci_dev *hdev = hci_pi(sk)->hdev; |
820 | + struct hci_dev *hdev = hci_hdev_from_sock(sk); |
821 | |
822 | - if (!hdev) |
823 | - return -EBADFD; |
824 | + if (IS_ERR(hdev)) |
825 | + return PTR_ERR(hdev); |
826 | |
827 | if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) |
828 | return -EBUSY; |
829 | @@ -1075,6 +1080,18 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, |
830 | |
831 | lock_sock(sk); |
832 | |
833 | + /* Allow detaching from dead device and attaching to alive device, if |
834 | + * the caller wants to re-bind (instead of close) this socket in |
835 | + * response to hci_sock_dev_event(HCI_DEV_UNREG) notification. |
836 | + */ |
837 | + hdev = hci_pi(sk)->hdev; |
838 | + if (hdev && hci_dev_test_flag(hdev, HCI_UNREGISTER)) { |
839 | + hci_pi(sk)->hdev = NULL; |
840 | + sk->sk_state = BT_OPEN; |
841 | + hci_dev_put(hdev); |
842 | + } |
843 | + hdev = NULL; |
844 | + |
845 | if (sk->sk_state == BT_BOUND) { |
846 | err = -EALREADY; |
847 | goto done; |
848 | @@ -1351,9 +1368,9 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, |
849 | |
850 | lock_sock(sk); |
851 | |
852 | - hdev = hci_pi(sk)->hdev; |
853 | - if (!hdev) { |
854 | - err = -EBADFD; |
855 | + hdev = hci_hdev_from_sock(sk); |
856 | + if (IS_ERR(hdev)) { |
857 | + err = PTR_ERR(hdev); |
858 | goto done; |
859 | } |
860 | |
861 | @@ -1713,9 +1730,9 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, |
862 | goto done; |
863 | } |
864 | |
865 | - hdev = hci_pi(sk)->hdev; |
866 | - if (!hdev) { |
867 | - err = -EBADFD; |
868 | + hdev = hci_hdev_from_sock(sk); |
869 | + if (IS_ERR(hdev)) { |
870 | + err = PTR_ERR(hdev); |
871 | goto done; |
872 | } |
873 | |
874 | diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c |
875 | index ca7a35ebaefb6..cb7d06bb0243c 100644 |
876 | --- a/net/bluetooth/hci_sysfs.c |
877 | +++ b/net/bluetooth/hci_sysfs.c |
878 | @@ -82,6 +82,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn) |
879 | static void bt_host_release(struct device *dev) |
880 | { |
881 | struct hci_dev *hdev = to_hci_dev(dev); |
882 | + |
883 | + if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) |
884 | + hci_cleanup_dev(hdev); |
885 | kfree(hdev); |
886 | module_put(THIS_MODULE); |
887 | } |
888 | diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py |
889 | index 30f117dfab438..68ecb455b4922 100755 |
890 | --- a/scripts/tracing/draw_functrace.py |
891 | +++ b/scripts/tracing/draw_functrace.py |
892 | @@ -17,7 +17,7 @@ Usage: |
893 | $ cat /sys/kernel/debug/tracing/trace_pipe > ~/raw_trace_func |
894 | Wait some times but not too much, the script is a bit slow. |
895 | Break the pipe (Ctrl + Z) |
896 | - $ scripts/draw_functrace.py < raw_trace_func > draw_functrace |
897 | + $ scripts/tracing/draw_functrace.py < ~/raw_trace_func > draw_functrace |
898 | Then you have your drawn trace in draw_functrace |
899 | """ |
900 | |
901 | @@ -103,10 +103,10 @@ def parseLine(line): |
902 | line = line.strip() |
903 | if line.startswith("#"): |
904 | raise CommentLineException |
905 | - m = re.match("[^]]+?\\] +([0-9.]+): (\\w+) <-(\\w+)", line) |
906 | + m = re.match("[^]]+?\\] +([a-z.]+) +([0-9.]+): (\\w+) <-(\\w+)", line) |
907 | if m is None: |
908 | raise BrokenLineException |
909 | - return (m.group(1), m.group(2), m.group(3)) |
910 | + return (m.group(2), m.group(3), m.group(4)) |
911 | |
912 | |
913 | def main(): |
914 | diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c |
915 | index 9cfe4fcee9a58..27433f141cee6 100644 |
916 | --- a/sound/core/seq/seq_ports.c |
917 | +++ b/sound/core/seq/seq_ports.c |
918 | @@ -532,10 +532,11 @@ static int check_and_subscribe_port(struct snd_seq_client *client, |
919 | return err; |
920 | } |
921 | |
922 | -static void delete_and_unsubscribe_port(struct snd_seq_client *client, |
923 | - struct snd_seq_client_port *port, |
924 | - struct snd_seq_subscribers *subs, |
925 | - bool is_src, bool ack) |
926 | +/* called with grp->list_mutex held */ |
927 | +static void __delete_and_unsubscribe_port(struct snd_seq_client *client, |
928 | + struct snd_seq_client_port *port, |
929 | + struct snd_seq_subscribers *subs, |
930 | + bool is_src, bool ack) |
931 | { |
932 | struct snd_seq_port_subs_info *grp; |
933 | struct list_head *list; |
934 | @@ -543,7 +544,6 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client, |
935 | |
936 | grp = is_src ? &port->c_src : &port->c_dest; |
937 | list = is_src ? &subs->src_list : &subs->dest_list; |
938 | - down_write(&grp->list_mutex); |
939 | write_lock_irq(&grp->list_lock); |
940 | empty = list_empty(list); |
941 | if (!empty) |
942 | @@ -553,6 +553,18 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client, |
943 | |
944 | if (!empty) |
945 | unsubscribe_port(client, port, grp, &subs->info, ack); |
946 | +} |
947 | + |
948 | +static void delete_and_unsubscribe_port(struct snd_seq_client *client, |
949 | + struct snd_seq_client_port *port, |
950 | + struct snd_seq_subscribers *subs, |
951 | + bool is_src, bool ack) |
952 | +{ |
953 | + struct snd_seq_port_subs_info *grp; |
954 | + |
955 | + grp = is_src ? &port->c_src : &port->c_dest; |
956 | + down_write(&grp->list_mutex); |
957 | + __delete_and_unsubscribe_port(client, port, subs, is_src, ack); |
958 | up_write(&grp->list_mutex); |
959 | } |
960 | |
961 | @@ -608,27 +620,30 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, |
962 | struct snd_seq_client_port *dest_port, |
963 | struct snd_seq_port_subscribe *info) |
964 | { |
965 | - struct snd_seq_port_subs_info *src = &src_port->c_src; |
966 | + struct snd_seq_port_subs_info *dest = &dest_port->c_dest; |
967 | struct snd_seq_subscribers *subs; |
968 | int err = -ENOENT; |
969 | |
970 | - down_write(&src->list_mutex); |
971 | + /* always start from deleting the dest port for avoiding concurrent |
972 | + * deletions |
973 | + */ |
974 | + down_write(&dest->list_mutex); |
975 | /* look for the connection */ |
976 | - list_for_each_entry(subs, &src->list_head, src_list) { |
977 | + list_for_each_entry(subs, &dest->list_head, dest_list) { |
978 | if (match_subs_info(info, &subs->info)) { |
979 | - atomic_dec(&subs->ref_count); /* mark as not ready */ |
980 | + __delete_and_unsubscribe_port(dest_client, dest_port, |
981 | + subs, false, |
982 | + connector->number != dest_client->number); |
983 | err = 0; |
984 | break; |
985 | } |
986 | } |
987 | - up_write(&src->list_mutex); |
988 | + up_write(&dest->list_mutex); |
989 | if (err < 0) |
990 | return err; |
991 | |
992 | delete_and_unsubscribe_port(src_client, src_port, subs, true, |
993 | connector->number != src_client->number); |
994 | - delete_and_unsubscribe_port(dest_client, dest_port, subs, false, |
995 | - connector->number != dest_client->number); |
996 | kfree(subs); |
997 | return 0; |
998 | } |