Date: Fri, 31 Jan 2003 17:15:34 +0100 (CET) From: Hartmut Brandt <brandt@fokus.fraunhofer.de> To: FreeBSD-gnats-submit@FreeBSD.org Subject: kern/47733: bus_dmamap_load_{mbuf,uio} broken if first buffer has zero length Message-ID: <200301311615.h0VGFYHC028939@catssrv.fokus.gmd.de>
next in thread | raw e-mail | index | archive | help
>Number: 47733 >Category: kern >Synopsis: bus_dmamap_load_{mbuf,uio} broken if first buffer has zero length >Confidential: no >Severity: serious >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Jan 31 08:20:11 PST 2003 >Closed-Date: >Last-Modified: >Originator: Hartmut Brandt >Release: FreeBSD 5.0-CURRENT sparc64 >Organization: Fraunhofer Fokus >Environment: System: FreeBSD catssrv.fokus.gmd.de 5.0-CURRENT FreeBSD 5.0-CURRENT #18: Tue Jan 28 11:49:32 CET 2003 hbb@catssrv.fokus.gmd.de:/opt/obj/usr/src/sys/CATSSRV sparc64 >Description: On all platforms bus_dmamap_load_{mbuf,uio} call bus_dmamap_load_buffer in a loop for each element. They maintain a variable 'first' which is set for the first element and cleared otherwise. This variable is passed to _load_buffer and in some circumstances this function instead of allocating a new DMA segment makes the previous one larger (if this is not the first element and the physical addresses are adjacent). If the first element (first mbuf or uio segment) has a zero size 'first' gets cleared although no segment was allocated by _load_buffer. If the physical addresses in the first elements are adjacent this results in _load_buffer clobbering the segment descriptors. >How-To-Repeat: Pass an mbuf chain where the first mbuf has m_len == 0 to an interface driver that uses bus_dmamap_load_mbuf. Under some circumstances this results in a hang or panic or other effects. >Fix: Apply the attached patches. It appears, that the problem is already fixed in the sparc/iommu code, but not in sparc/nexus and not on all other platforms. The i386 patch has been tested. The others not. Index: sys/alpha/alpha/busdma_machdep.c =================================================================== RCS file: /home/cvs/freebsd/src/sys/alpha/alpha/busdma_machdep.c,v retrieving revision 1.25 diff -c -r1.25 busdma_machdep.c *** sys/alpha/alpha/busdma_machdep.c 21 Jan 2003 08:55:22 -0000 1.25 --- sys/alpha/alpha/busdma_machdep.c 31 Jan 2003 16:05:44 -0000 *************** *** 658,668 **** struct mbuf *m; for (m = m0; m != NULL && error == 0; m = m->m_next) { ! error = _bus_dmamap_load_buffer(dmat, ! dm_segments, ! m->m_data, m->m_len, ! NULL, flags, &lastaddr, &nsegs, first); ! first = 0; } } else { error = EINVAL; --- 658,671 ---- struct mbuf *m; for (m = m0; m != NULL && error == 0; m = m->m_next) { ! if (m->m_len > 0) { ! error = _bus_dmamap_load_buffer(dmat, ! dm_segments, ! m->m_data, m->m_len, ! NULL, flags, &lastaddr, ! &nsegs, first); ! first = 0; ! } } } else { error = EINVAL; *************** *** 722,734 **** resid < iov[i].iov_len ? resid : iov[i].iov_len; caddr_t addr = (caddr_t) iov[i].iov_base; ! error = _bus_dmamap_load_buffer(dmat, ! dm_segments, ! addr, minlen, ! td, flags, &lastaddr, &nsegs, first); ! first = 0; ! resid -= minlen; } if (error) { --- 725,739 ---- resid < iov[i].iov_len ? resid : iov[i].iov_len; caddr_t addr = (caddr_t) iov[i].iov_base; ! if (minlen > 0) { ! error = _bus_dmamap_load_buffer(dmat, ! dm_segments, ! addr, minlen, ! td, flags, &lastaddr, &nsegs, first); ! first = 0; ! resid -= minlen; ! } } if (error) { Index: sys/i386/i386/busdma_machdep.c =================================================================== RCS file: /home/cvs/freebsd/src/sys/i386/i386/busdma_machdep.c,v retrieving revision 1.29 diff -c -r1.29 busdma_machdep.c *** sys/i386/i386/busdma_machdep.c 21 Jan 2003 08:55:50 -0000 1.29 --- sys/i386/i386/busdma_machdep.c 31 Jan 2003 16:05:44 -0000 *************** *** 616,626 **** struct mbuf *m; for (m = m0; m != NULL && error == 0; m = m->m_next) { ! error = _bus_dmamap_load_buffer(dmat, ! dm_segments, ! m->m_data, m->m_len, ! NULL, flags, &lastaddr, &nsegs, first); ! first = 0; } } else { error = EINVAL; --- 616,628 ---- struct mbuf *m; for (m = m0; m != NULL && error == 0; m = m->m_next) { ! if (m->m_len > 0) { ! error = _bus_dmamap_load_buffer(dmat, ! dm_segments, ! m->m_data, m->m_len, ! NULL, flags, &lastaddr, &nsegs, first); ! first = 0; ! } } } else { error = EINVAL; *************** *** 680,692 **** resid < iov[i].iov_len ? resid : iov[i].iov_len; caddr_t addr = (caddr_t) iov[i].iov_base; ! error = _bus_dmamap_load_buffer(dmat, ! dm_segments, ! addr, minlen, ! td, flags, &lastaddr, &nsegs, first); ! first = 0; ! resid -= minlen; } if (error) { --- 682,696 ---- resid < iov[i].iov_len ? resid : iov[i].iov_len; caddr_t addr = (caddr_t) iov[i].iov_base; ! if (minlen > 0) { ! error = _bus_dmamap_load_buffer(dmat, ! dm_segments, ! addr, minlen, ! td, flags, &lastaddr, &nsegs, first); ! first = 0; ! resid -= minlen; ! } } if (error) { Index: sys/powerpc/powerpc/busdma_machdep.c =================================================================== RCS file: /home/cvs/freebsd/src/sys/powerpc/powerpc/busdma_machdep.c,v retrieving revision 1.5 diff -c -r1.5 busdma_machdep.c *** sys/powerpc/powerpc/busdma_machdep.c 27 Jan 2003 04:27:01 -0000 1.5 --- sys/powerpc/powerpc/busdma_machdep.c 31 Jan 2003 16:05:44 -0000 *************** *** 423,432 **** struct mbuf *m; for (m = m0; m != NULL && error == 0; m = m->m_next) { ! error = bus_dmamap_load_buffer(dmat, dm_segments, ! m->m_data, m->m_len, NULL, flags, ! &lastaddr, &nsegs, first); ! first = 0; } } else { error = EINVAL; --- 423,434 ---- struct mbuf *m; for (m = m0; m != NULL && error == 0; m = m->m_next) { ! if (m->m_len > 0) { ! error = bus_dmamap_load_buffer(dmat, ! dm_segments, m->m_data, m->m_len, NULL, ! flags, &lastaddr, &nsegs, first); ! first = 0; ! } } } else { error = EINVAL; *************** *** 483,494 **** resid < iov[i].iov_len ? resid : iov[i].iov_len; caddr_t addr = (caddr_t) iov[i].iov_base; ! error = bus_dmamap_load_buffer(dmat, dm_segments, addr, ! minlen, td, flags, &lastaddr, &nsegs, first); ! first = 0; ! resid -= minlen; } if (error) { --- 485,498 ---- resid < iov[i].iov_len ? resid : iov[i].iov_len; caddr_t addr = (caddr_t) iov[i].iov_base; ! if (minlen > 0) { ! error = bus_dmamap_load_buffer(dmat, dm_segments, addr, ! minlen, td, flags, &lastaddr, &nsegs, first); ! first = 0; ! resid -= minlen; ! } } if (error) { Index: sys/sparc64/sparc64/bus_machdep.c =================================================================== RCS file: /home/cvs/freebsd/src/sys/sparc64/sparc64/bus_machdep.c,v retrieving revision 1.16 diff -c -r1.16 bus_machdep.c *** sys/sparc64/sparc64/bus_machdep.c 21 Jan 2003 08:56:14 -0000 1.16 --- sys/sparc64/sparc64/bus_machdep.c 31 Jan 2003 16:05:44 -0000 *************** *** 448,457 **** struct mbuf *m; for (m = m0; m != NULL && error == 0; m = m->m_next) { ! error = _nexus_dmamap_load_buffer(ddmat, ! dm_segments, m->m_data, m->m_len, NULL, flags, ! &lastaddr, &nsegs, first); ! first = 0; } } else { error = EINVAL; --- 448,459 ---- struct mbuf *m; for (m = m0; m != NULL && error == 0; m = m->m_next) { ! if (m->m_len > 0) { ! error = _nexus_dmamap_load_buffer(ddmat, ! dm_segments, m->m_data, m->m_len, NULL, ! flags, &lastaddr, &nsegs, first); ! first = 0; ! } } } else { error = EINVAL; *************** *** 508,518 **** resid < iov[i].iov_len ? resid : iov[i].iov_len; caddr_t addr = (caddr_t) iov[i].iov_base; ! error = _nexus_dmamap_load_buffer(ddmat, dm_segments, addr, ! minlen, td, flags, &lastaddr, &nsegs, first); ! first = 0; ! resid -= minlen; } if (error) { --- 510,522 ---- resid < iov[i].iov_len ? resid : iov[i].iov_len; caddr_t addr = (caddr_t) iov[i].iov_base; ! if (minlen > 0) { ! error = _nexus_dmamap_load_buffer(ddmat, dm_segments, ! addr, minlen, td, flags, &lastaddr, &nsegs, first); ! first = 0; ! resid -= minlen; ! } } if (error) { >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200301311615.h0VGFYHC028939>