From owner-svn-src-all@FreeBSD.ORG Sun May 24 13:22:00 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id BFA7B106566C; Sun, 24 May 2009 13:22:00 +0000 (UTC) (envelope-from dfr@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id A37EC8FC08; Sun, 24 May 2009 13:22:00 +0000 (UTC) (envelope-from dfr@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n4ODM0T4090868; Sun, 24 May 2009 13:22:00 GMT (envelope-from dfr@svn.freebsd.org) Received: (from dfr@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n4ODM0B2090867; Sun, 24 May 2009 13:22:00 GMT (envelope-from dfr@svn.freebsd.org) Message-Id: <200905241322.n4ODM0B2090867@svn.freebsd.org> From: Doug Rabson Date: Sun, 24 May 2009 13:22:00 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r192686 - head/sys/nfsclient X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 24 May 2009 13:22:01 -0000 Author: dfr Date: Sun May 24 13:22:00 2009 New Revision: 192686 URL: http://svn.freebsd.org/changeset/base/192686 Log: Make sure we feed 32bit align memory to nfsm_dissect otherwise we will fault on platforms with strict alignment requirements. In particular, this fixes the problems with the new RPC transport on the arm platform. Note: this adds yet another copy of nfs_realign(). I will attempt to refactor after NFS_LEGACYRPC is removed. Submitted by: sam Modified: head/sys/nfsclient/nfs_krpc.c Modified: head/sys/nfsclient/nfs_krpc.c ============================================================================== --- head/sys/nfsclient/nfs_krpc.c Sun May 24 12:39:38 2009 (r192685) +++ head/sys/nfsclient/nfs_krpc.c Sun May 24 13:22:00 2009 (r192686) @@ -407,6 +407,65 @@ nfs_feedback(int type, int proc, void *a } /* + * nfs_realign: + * + * Check for badly aligned mbuf data and realign by copying the unaligned + * portion of the data into a new mbuf chain and freeing the portions + * of the old chain that were replaced. + * + * We cannot simply realign the data within the existing mbuf chain + * because the underlying buffers may contain other rpc commands and + * we cannot afford to overwrite them. + * + * We would prefer to avoid this situation entirely. The situation does + * not occur with NFS/UDP and is supposed to only occassionally occur + * with TCP. Use vfs.nfs.realign_count and realign_test to check this. + * + */ +static int +nfs_realign(struct mbuf **pm, int hsiz) +{ + struct mbuf *m, *n; + int off, space; + + ++nfs_realign_test; + while ((m = *pm) != NULL) { + if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) { + /* + * NB: we can't depend on m_pkthdr.len to help us + * decide what to do here. May not be worth doing + * the m_length calculation as m_copyback will + * expand the mbuf chain below as needed. + */ + space = m_length(m, NULL); + if (space >= MINCLSIZE) { + /* NB: m_copyback handles space > MCLBYTES */ + n = m_getcl(M_DONTWAIT, MT_DATA, 0); + } else + n = m_get(M_DONTWAIT, MT_DATA); + if (n == NULL) + return (ENOMEM); + /* + * Align the remainder of the mbuf chain. + */ + n->m_len = 0; + off = 0; + while (m != NULL) { + m_copyback(n, off, m->m_len, mtod(m, caddr_t)); + off += m->m_len; + m = m->m_next; + } + m_freem(*pm); + *pm = n; + ++nfs_realign_count; + break; + } + pm = &m->m_next; + } + return (0); +} + +/* * nfs_request - goes something like this * - fill in request struct * - links it into list @@ -525,12 +584,25 @@ tryagain: } else { error = EACCES; } - md = mrep; if (error) goto nfsmout; KASSERT(mrep != NULL, ("mrep shouldn't be NULL if no error\n")); + /* + * Search for any mbufs that are not a multiple of 4 bytes long + * or with m_data not longword aligned. + * These could cause pointer alignment problems, so copy them to + * well aligned mbufs. + */ + error = nfs_realign(&mrep, 2 * NFSX_UNSIGNED); + if (error == ENOMEM) { + m_freem(mrep); + AUTH_DESTROY(auth); + return (error); + } + + md = mrep; dpos = mtod(mrep, caddr_t); tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED); if (*tl != 0) {