summaryrefslogtreecommitdiff
path: root/sys/nfs
diff options
context:
space:
mode:
authorPedro Martelletto <pedro@cvs.openbsd.org>2006-08-04 12:35:58 +0000
committerPedro Martelletto <pedro@cvs.openbsd.org>2006-08-04 12:35:58 +0000
commit29d4b9c33e298d700a526b9c4a65dd4a49c5945f (patch)
tree8a00f7e5df0197450859334279fb6fda0cc563d2 /sys/nfs
parent8e8fe6daa4a7b238cd227f2b3a5f4f487517664f (diff)
Fix up mbuf length and do 64-bit alignment where needed, joint work
with Nicholas Marriott <nicm__@ntlworld.com>, closes PR 5036
Diffstat (limited to 'sys/nfs')
-rw-r--r--sys/nfs/nfs_socket.c59
1 files changed, 54 insertions, 5 deletions
diff --git a/sys/nfs/nfs_socket.c b/sys/nfs/nfs_socket.c
index 77fa523d219..74b88487179 100644
--- a/sys/nfs/nfs_socket.c
+++ b/sys/nfs/nfs_socket.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_socket.c,v 1.43 2006/01/24 15:06:41 aaron Exp $ */
+/* $OpenBSD: nfs_socket.c,v 1.44 2006/08/04 12:35:57 pedro Exp $ */
/* $NetBSD: nfs_socket.c,v 1.27 1996/04/15 20:20:00 thorpej Exp $ */
/*
@@ -133,6 +133,7 @@ int nfsrtton = 0;
struct nfsrtt nfsrtt;
void nfs_realign(struct mbuf **, int);
+void nfs_realign_fixup(struct mbuf *, struct mbuf *, unsigned int *);
unsigned int nfs_realign_test = 0;
unsigned int nfs_realign_count = 0;
@@ -1454,20 +1455,60 @@ nfs_rcvunlock(flagp)
}
/*
- * NFS parsing code requires 32-bit alignment
+ * Auxiliary routine to align the length of mbuf copies made with m_copyback().
+ */
+void
+nfs_realign_fixup(struct mbuf *m, struct mbuf *n, unsigned int *off)
+{
+ size_t padding;
+
+ /*
+ * The maximum number of bytes that m_copyback() places in a mbuf is
+ * always an aligned quantity, so realign happens at the chain's tail.
+ */
+ while (n->m_next != NULL)
+ n = n->m_next;
+
+ /*
+ * Pad from the next elements in the source chain. Loop until the
+ * destination chain is aligned, or the end of the source is reached.
+ */
+ do {
+ m = m->m_next;
+ if (m == NULL)
+ return;
+
+ padding = min(ALIGN(n->m_len) - n->m_len, m->m_len);
+ if (padding > M_TRAILINGSPACE(n))
+ panic("nfs_realign_fixup: no memory to pad to");
+
+ bcopy(mtod(m, void *), mtod(n, char *) + n->m_len, padding);
+
+ n->m_len += padding;
+ m_adj(m, padding);
+ *off += padding;
+
+ } while (!ALIGNED_POINTER(n->m_len, void *));
+}
+
+/*
+ * The NFS RPC parsing code uses the data address and the length of mbuf
+ * structures to calculate on-memory addresses. This function makes sure these
+ * parameters are correctly aligned.
*/
void
nfs_realign(struct mbuf **pm, int hsiz)
{
struct mbuf *m;
struct mbuf *n = NULL;
- int off = 0;
+ unsigned int off = 0;
++nfs_realign_test;
while ((m = *pm) != NULL) {
- if ((m->m_len & 0x3) || (mtod(m, long) & 0x3)) {
+ if (!ALIGNED_POINTER(m->m_data, void *) ||
+ !ALIGNED_POINTER(m->m_len, void *)) {
MGET(n, M_WAIT, MT_DATA);
- if (m->m_len >= MINCLSIZE) {
+ if (ALIGN(m->m_len) >= MINCLSIZE) {
MCLGET(n, M_WAIT);
}
n->m_len = 0;
@@ -1483,6 +1524,14 @@ nfs_realign(struct mbuf **pm, int hsiz)
++nfs_realign_count;
while (m) {
m_copyback(n, off, m->m_len, mtod(m, caddr_t));
+
+ /*
+ * If an unaligned amount of memory was copied, fix up
+ * the last mbuf created by m_copyback().
+ */
+ if (!ALIGNED_POINTER(m->m_len, void *))
+ nfs_realign_fixup(m, n, &off);
+
off += m->m_len;
m = m->m_next;
}