Date: Wed, 4 Mar 2015 15:00:21 +0000 (UTC) From: Gleb Smirnoff <glebius@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r279592 - head/sys/net Message-ID: <201503041500.t24F0LGu005096@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: glebius Date: Wed Mar 4 15:00:20 2015 New Revision: 279592 URL: https://svnweb.freebsd.org/changeset/base/279592 Log: Optimize SIOCGIFMEDIA handling removing malloc(9) and double traversal of the list. Sponsored by: Nginx, Inc. Sponsored by: Netflix Modified: head/sys/net/if_media.c Modified: head/sys/net/if_media.c ============================================================================== --- head/sys/net/if_media.c Wed Mar 4 14:30:09 2015 (r279591) +++ head/sys/net/if_media.c Wed Mar 4 15:00:20 2015 (r279592) @@ -204,7 +204,7 @@ ifmedia_ioctl(ifp, ifr, ifm, cmd) { struct ifmedia_entry *match; struct ifmediareq *ifmr = (struct ifmediareq *) ifr; - int error = 0, sticky; + int error = 0; if (ifp == NULL || ifr == NULL || ifm == NULL) return(EINVAL); @@ -273,10 +273,10 @@ ifmedia_ioctl(ifp, ifr, ifm, cmd) case SIOCGIFMEDIA: { struct ifmedia_entry *ep; - int *kptr, count; - int usermax; /* user requested max */ + int i; - kptr = NULL; /* XXX gcc */ + if (ifmr->ifm_count < 0) + return (EINVAL); ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ? ifm->ifm_cur->ifm_media : IFM_NONE; @@ -284,67 +284,23 @@ ifmedia_ioctl(ifp, ifr, ifm, cmd) ifmr->ifm_status = 0; (*ifm->ifm_status)(ifp, ifmr); - count = 0; - usermax = 0; - /* * If there are more interfaces on the list, count * them. This allows the caller to set ifmr->ifm_count * to 0 on the first call to know how much space to * allocate. */ + i = 0; LIST_FOREACH(ep, &ifm->ifm_list, ifm_list) - usermax++; - - /* - * Don't allow the user to ask for too many - * or a negative number. - */ - if (ifmr->ifm_count > usermax) - ifmr->ifm_count = usermax; - else if (ifmr->ifm_count < 0) - return (EINVAL); - - if (ifmr->ifm_count != 0) { - kptr = (int *)malloc(ifmr->ifm_count * sizeof(int), - M_TEMP, M_NOWAIT); - - if (kptr == NULL) - return (ENOMEM); - /* - * Get the media words from the interface's list. - */ - ep = LIST_FIRST(&ifm->ifm_list); - for (; ep != NULL && count < ifmr->ifm_count; - ep = LIST_NEXT(ep, ifm_list), count++) - kptr[count] = ep->ifm_media; - - if (ep != NULL) - error = E2BIG; /* oops! */ - } else { - count = usermax; - } - - /* - * We do the copyout on E2BIG, because that's - * just our way of telling userland that there - * are more. This is the behavior I've observed - * under BSD/OS 3.0 - */ - sticky = error; - if ((error == 0 || error == E2BIG) && ifmr->ifm_count != 0) { - error = copyout((caddr_t)kptr, - (caddr_t)ifmr->ifm_ulist, - ifmr->ifm_count * sizeof(int)); - } - - if (error == 0) - error = sticky; - - if (ifmr->ifm_count != 0) - free(kptr, M_TEMP); - - ifmr->ifm_count = count; + if (i++ < ifmr->ifm_count) { + error = copyout(&ep->ifm_media, + ifmr->ifm_ulist + i - 1, sizeof(int)); + if (error) + break; + } + if (error == 0 && i > ifmr->ifm_count) + error = ifmr->ifm_count ? E2BIG : 0; + ifmr->ifm_count = i; break; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201503041500.t24F0LGu005096>