Skip site navigation (1)Skip section navigation (2)
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>