From owner-freebsd-bugs Fri Jan 31 8:20:33 2003 Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 6933737B401 for ; Fri, 31 Jan 2003 08:20:25 -0800 (PST) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 8036B43F85 for ; Fri, 31 Jan 2003 08:20:13 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.12.6/8.12.6) with ESMTP id h0VGKDNS083101 for ; Fri, 31 Jan 2003 08:20:13 -0800 (PST) (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.6/8.12.6/Submit) id h0VGKDJX083100; Fri, 31 Jan 2003 08:20:13 -0800 (PST) Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id EEBD437B401 for ; Fri, 31 Jan 2003 08:15:42 -0800 (PST) Received: from mailhub.fokus.gmd.de (mailhub.fokus.gmd.de [193.174.154.14]) by mx1.FreeBSD.org (Postfix) with ESMTP id AE17743E4A for ; Fri, 31 Jan 2003 08:15:41 -0800 (PST) (envelope-from hbb@catssrv.fokus.gmd.de) Received: from catssrv.fokus.gmd.de (catssrv [192.168.229.23]) by mailhub.fokus.gmd.de (8.11.6/8.11.6) with ESMTP id h0VGFYi24994 for ; Fri, 31 Jan 2003 17:15:34 +0100 (MET) Received: from catssrv.fokus.gmd.de (localhost [127.0.0.1]) by catssrv.fokus.gmd.de (8.12.6/8.12.6) with ESMTP id h0VGFYRv028940 for ; Fri, 31 Jan 2003 17:15:34 +0100 (CET) (envelope-from hbb@catssrv.fokus.gmd.de) Received: (from root@localhost) by catssrv.fokus.gmd.de (8.12.6/8.12.6/Submit) id h0VGFYHC028939; Fri, 31 Jan 2003 17:15:34 +0100 (CET) (envelope-from hbb) Message-Id: <200301311615.h0VGFYHC028939@catssrv.fokus.gmd.de> Date: Fri, 31 Jan 2003 17:15:34 +0100 (CET) From: Hartmut Brandt Reply-To: Hartmut Brandt To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Subject: kern/47733: bus_dmamap_load_{mbuf,uio} broken if first buffer has zero length Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org >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