unp_internalize() tries to resize a mbuf by calling MCLGET() and then copying the mbuf data into the extcluster allocated over the mbuf. This fails badly since the exthdr is put into the data section of the mbuf. So instead copy out the data into temporary storage and then copy back after succesful cluster allocation.
This fixes a problem when trying to pass more then 26 fds on amd64. -- :wq Claudio Index: kern//uipc_usrreq.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_usrreq.c,v retrieving revision 1.57 diff -u -p -r1.57 uipc_usrreq.c --- kern//uipc_usrreq.c 13 Apr 2012 09:38:32 -0000 1.57 +++ kern//uipc_usrreq.c 13 Apr 2012 15:31:27 -0000 @@ -783,18 +783,24 @@ morespace: neededspace = CMSG_SPACE(nfds * sizeof(struct file *)) - control->m_len; if (neededspace > M_TRAILINGSPACE(control)) { + char *tmp; /* if we already have a cluster, the message is just too big */ if (control->m_flags & M_EXT) return (E2BIG); + /* copy cmsg data temporarily out of the mbuf */ + tmp = malloc(control->m_len, M_TEMP, M_WAITOK); + memcpy(tmp, mtod(control, caddr_t), control->m_len); + /* allocate a cluster and try again */ MCLGET(control, M_WAIT); if ((control->m_flags & M_EXT) == 0) return (ENOBUFS); /* allocation failed */ - /* copy the data to the cluster */ - memcpy(mtod(control, char *), cm, cm->cmsg_len); + /* copy the data back into the cluster */ cm = mtod(control, struct cmsghdr *); + memcpy(cm, tmp, control->m_len); + free(tmp, M_TEMP); goto morespace; }