Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/kern Avoid using m_clget() on a mbuf already in use, esp...



details:   https://anonhg.NetBSD.org/src/rev/7cb85c1980d5
branches:  trunk
changeset: 556902:7cb85c1980d5
user:      martin <martin%NetBSD.org@localhost>
date:      Mon Dec 29 22:08:02 2003 +0000

description:
Avoid using m_clget() on a mbuf already in use, especially when we
need the data in the mbuf later and m_clget() changes some fields
overlaid to regular mbuf data. Instead, rearange code a bit, create
data into a new allocated buffer and and use MEXTADD to attach it to
the mbuf, if the mbuf internal space is not sufficient.

This fixes a crash on sparc64 (and probably all other archs where
sizeof(int) != sizeof(struct file *)) when running
regress/sys/kern/unfdpass.

Idea for solution from Matt Thomas, with additional input from YAMAMOTO
Takashi.

diffstat:

 sys/kern/uipc_usrreq.c |  54 ++++++++++++++++++++++++++++---------------------
 1 files changed, 31 insertions(+), 23 deletions(-)

diffs (101 lines):

diff -r bc7adbd1b55d -r 7cb85c1980d5 sys/kern/uipc_usrreq.c
--- a/sys/kern/uipc_usrreq.c    Mon Dec 29 21:21:25 2003 +0000
+++ b/sys/kern/uipc_usrreq.c    Mon Dec 29 22:08:02 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uipc_usrreq.c,v 1.72 2003/11/29 10:02:42 matt Exp $    */
+/*     $NetBSD: uipc_usrreq.c,v 1.73 2003/12/29 22:08:02 martin Exp $  */
 
 /*-
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -103,7 +103,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.72 2003/11/29 10:02:42 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.73 2003/12/29 22:08:02 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -974,8 +974,8 @@
        struct proc *p;
 {
        struct filedesc *fdescp = p->p_fd;
-       struct cmsghdr *cm = mtod(control, struct cmsghdr *);
-       struct file **rp;
+       struct cmsghdr *newcm, *cm = mtod(control, struct cmsghdr *);
+       struct file **rp, **files;
        struct file *fp;
        int i, fd, *fdp;
        int nfds;
@@ -997,37 +997,31 @@
        }
 
        /* Make sure we have room for the struct file pointers */
- morespace:
        neededspace = CMSG_SPACE(nfds * sizeof(struct file *)) -
            control->m_len;
        if (neededspace > M_TRAILINGSPACE(control)) {
 
-               /* if we already have a cluster, the message is just too big */
-               if (control->m_flags & M_EXT)
+               /* allocate new space and copy header into it */
+               newcm = malloc(
+                   CMSG_SPACE(nfds * sizeof(struct file *)),
+                   M_MBUF, M_WAITOK);
+               if (newcm == NULL)
                        return (E2BIG);
-
-               /* allocate a cluster and try again */
-               m_clget(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);
-               cm = mtod(control, struct cmsghdr *);
-               goto morespace;
+               memcpy(newcm, cm, sizeof(struct cmsghdr));
+               files = (struct file **)CMSG_DATA(newcm);               
+       } else {
+               /* we can convert in-place */
+               newcm = NULL;
+               files = (struct file **)CMSG_DATA(cm);
        }
 
-       /* adjust message & mbuf to note amount of space actually used. */
-       cm->cmsg_len = CMSG_LEN(nfds * sizeof(struct file *));
-       control->m_len = CMSG_SPACE(nfds * sizeof(struct file *));
-
        /*
         * Transform the file descriptors into struct file pointers, in
         * reverse order so that if pointers are bigger than ints, the
         * int won't get until we're done.
         */
-       fdp = ((int *)CMSG_DATA(cm)) + nfds - 1;
-       rp = ((struct file **)CMSG_DATA(cm)) + nfds - 1;
+       fdp = (int *)CMSG_DATA(cm) + nfds - 1;
+       rp = files + nfds - 1;
        for (i = 0; i < nfds; i++) {
                fp = fdescp->fd_ofiles[*fdp--];
                simple_lock(&fp->f_slock);
@@ -1041,6 +1035,20 @@
                simple_unlock(&fp->f_slock);
                unp_rights++;
        }
+
+       if (newcm) {
+               if (control->m_flags & M_EXT)
+                       MEXTREMOVE(control);
+               MEXTADD(control, newcm,
+                   CMSG_SPACE(nfds * sizeof(struct file *)),
+                   M_MBUF, NULL, NULL);
+               cm = newcm;
+       }
+
+       /* adjust message & mbuf to note amount of space actually used. */
+       cm->cmsg_len = CMSG_LEN(nfds * sizeof(struct file *));
+       control->m_len = CMSG_SPACE(nfds * sizeof(struct file *));
+
        return (0);
 }
 



Home | Main Index | Thread Index | Old Index