From 7675fe99d280ea83388a4382c54573c80db37cda Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 21 Nov 2014 06:20:56 -0300 Subject: [PATCH] [media] cx23885: use sg = sg_next(sg) instead of sg++ The cx23885 driver still used sg++ instead of sg = sg_next(sg). This worked with vb1 since that filled in the sglist manually, page-by-page, but it fails with vb2 which uses core scatterlist code that can combine contiguous scatterlist entries into one larger entry. This bug led to the following crash as reported by Mariusz: [20712.990258] BUG: Bad page state in process vb2-cx23885[0] pfn:2ca34 [20712.990265] page:ffffea00009c3b60 count:-1 mapcount:0 mapping: (null) index:0x0 [20712.990266] flags: 0x4000000000000000() [20712.990268] page dumped because: nonzero _count [20712.990269] Modules linked in: tun binfmt_misc nf_conntrack_ipv6 nf_defrag_ipv6 ip6table_filter ip6_tables xt_mark xt_REDIRECT xt_limit xt_conntrack xt_nat xt_tcpudp iptable_mangle iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_filter ip_tables x_tables sit ip_tunnel nvidia(PO) stb6100 stv090x cx88_dvb videobuf_dvb cx88_vp3054_i2c tuner kvm_amd kvm cx8802 k10temp cx8800 cx88xx btcx_risc videobuf_dma_sg videobuf_core usb_storage ds2490 usbhid ftdi_sio cx23885 tveeprom cx2341x videobuf2_dvb videobuf2_core videobuf2_dma_sg videobuf2_memops asus_atk0110 snd_emu10k1 snd_hwdep snd_util_mem snd_ac97_codec ac97_bus snd_rawmidi snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd w1_therm wire ipv6 [20712.990301] CPU: 2 PID: 26942 Comm: vb2-cx23885[0] Tainted: P B W O 3.18.0-rc5-00001-gb3652d1 #2 [20712.990303] Hardware name: System manufacturer System Product Name/M4A785TD-V EVO, BIOS 2105 07/23/2010 [20712.990305] ffffffff81765734 ffff880137683a78 ffffffff815b6b32 0000000000000006 [20712.990307] ffffea00009c3b60 ffff880137683aa8 ffffffff8108ec27 ffffffff81765712 [20712.990309] ffffffff8189c840 0000000000000246 ffffea00009c3b60 ffff880137683b78 [20712.990312] Call Trace: [20712.990317] [] dump_stack+0x46/0x58 [20712.990321] [] bad_page+0xe9/0x107 [20712.990323] [] get_page_from_freelist+0x3b2/0x505 [20712.990326] [] __alloc_pages_nodemask+0xed/0x65f [20712.990330] [] ? ttwu_do_activate.constprop.78+0x57/0x5c [20712.990332] [] ? try_to_wake_up+0x21b/0x22d [20712.990336] [] dma_generic_alloc_coherent+0x6e/0xf5 [20712.990339] [] gart_alloc_coherent+0x105/0x114 [20712.990341] [] ? flush_gart+0x39/0x3d [20712.990343] [] ? gart_map_sg+0x3a0/0x3a0 [20712.990349] [] cx23885_risc_databuffer+0xa7/0x133 [cx23885] [20712.990354] [] cx23885_buf_prepare+0x121/0x134 [cx23885] [20712.990359] [] buffer_prepare+0x14/0x16 [cx23885] [20712.990363] [] __buf_prepare+0x190/0x279 [videobuf2_core] [20712.990366] [] ? vb2_queue_or_prepare_buf+0xb8/0xc0 [videobuf2_core] [20712.990369] [] vb2_internal_qbuf+0x51/0x1e5 [videobuf2_core] [20712.990372] [] vb2_thread+0x199/0x1f6 [videobuf2_core] [20712.990376] [] ? vb2_fop_write+0xdf/0xdf [videobuf2_core] [20712.990379] [] kthread+0xdf/0xe7 [20712.990381] [] ? kthread_create_on_node+0x16d/0x16d [20712.990384] [] ret_from_fork+0x7c/0xb0 [20712.990386] [] ? kthread_create_on_node+0x16d/0x16d Signed-off-by: Hans Verkuil Reported-by: Mariusz Bialonczyk Tested-by: Mariusz Bialonczyk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 331eddac7222..3bd386c371f7 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -1078,7 +1078,7 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, for (line = 0; line < lines; line++) { while (offset && offset >= sg_dma_len(sg)) { offset -= sg_dma_len(sg); - sg++; + sg = sg_next(sg); } if (lpi && line > 0 && !(line % lpi)) @@ -1101,14 +1101,14 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, *(rp++) = cpu_to_le32(0); /* bits 63-32 */ todo -= (sg_dma_len(sg)-offset); offset = 0; - sg++; + sg = sg_next(sg); while (todo > sg_dma_len(sg)) { *(rp++) = cpu_to_le32(RISC_WRITE| sg_dma_len(sg)); *(rp++) = cpu_to_le32(sg_dma_address(sg)); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ todo -= sg_dma_len(sg); - sg++; + sg = sg_next(sg); } *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo); *(rp++) = cpu_to_le32(sg_dma_address(sg)); -- 2.34.1