public inbox for libc-hacker@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Better fix for ifaddrs
@ 2007-03-14 18:16 Jakub Jelinek
  2007-03-15  0:45 ` Ulrich Drepper
  0 siblings, 1 reply; 3+ messages in thread
From: Jakub Jelinek @ 2007-03-14 18:16 UTC (permalink / raw)
  To: Ulrich Drepper; +Cc: Glibc hackers

Hi!

David Miller said kernel guarantees that netlink requests are split into at
most page sized chunks.
This patch removes again all the MSG_TRUNC handling and instead uses page
sized buffer.  I believe a page should be ok with alloca/VLA always, so I
have removed even the use_malloc etc. stuff, if you think I should use
__libc_use_alloca even for this, please let me know.
Tested on ia64 with 80 interfaces.

2007-03-14  Jakub Jelinek  <jakub@redhat.com>

	* sysdeps/unix/sysv/linux/ifaddrs.c (__netlink_request): Revert
	2005-06-13, 2007-02-27 and 2007-03-02 changes.  Use page sized buffer.
	* sysdeps/unix/sysv/linux/check_pf.c (make_request): Use page sized
	buffer.

--- libc/sysdeps/unix/sysv/linux/check_pf.c.jj	2007-01-03 11:04:37.000000000 +0100
+++ libc/sysdeps/unix/sysv/linux/check_pf.c	2007-03-13 18:16:12.000000000 +0100
@@ -1,5 +1,5 @@
 /* Determine protocol families for which interfaces exist.  Linux version.
-   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -80,8 +80,9 @@ make_request (int fd, pid_t pid, bool *s
   *seen_ipv6 = false;
 
   bool done = false;
-  char buf[4096];
-  struct iovec iov = { buf, sizeof (buf) };
+  size_t buf_size = __getpagesize ();
+  char buf[buf_size];
+  struct iovec iov = { buf, buf_size };
   struct in6ailist
   {
     struct in6addrinfo info;
--- libc/sysdeps/unix/sysv/linux/ifaddrs.c.jj	2007-03-13 17:42:17.000000000 +0100
+++ libc/sysdeps/unix/sysv/linux/ifaddrs.c	2007-03-13 18:17:06.000000000 +0100
@@ -122,37 +122,17 @@ int
 __netlink_request (struct netlink_handle *h, int type)
 {
   struct netlink_res *nlm_next;
-  struct netlink_res **new_nlm_list;
-  static volatile size_t buf_size = 4096;
-  char *buf;
+  size_t buf_size = __getpagesize ();
+  char buf[buf_size];
   struct sockaddr_nl nladdr;
   struct nlmsghdr *nlmh;
   ssize_t read_len;
   bool done = false;
-  bool use_malloc = false;
 
   if (__netlink_sendreq (h, type) < 0)
     return -1;
 
-  size_t this_buf_size = buf_size;
-  size_t orig_this_buf_size = this_buf_size;
-  if (__libc_use_alloca (this_buf_size))
-    buf = alloca (this_buf_size);
-  else
-    {
-      buf = malloc (this_buf_size);
-      if (buf != NULL)
-	use_malloc = true;
-      else
-	goto out_fail;
-    }
-
-  struct iovec iov = { buf, this_buf_size };
-
-  if (h->nlm_list != NULL)
-    new_nlm_list = &h->end_ptr->next;
-  else
-    new_nlm_list = &h->nlm_list;
+  struct iovec iov = { buf, buf_size };
 
   while (! done)
     {
@@ -166,54 +146,13 @@ __netlink_request (struct netlink_handle
 
       read_len = TEMP_FAILURE_RETRY (__recvmsg (h->fd, &msg, 0));
       if (read_len < 0)
-	goto out_fail;
+	return -1;
 
       if (nladdr.nl_pid != 0)
 	continue;
 
       if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0))
-	{
-	  if (this_buf_size >= SIZE_MAX / 2)
-	    goto out_fail;
-
-	  nlm_next = *new_nlm_list;
-	  while (nlm_next != NULL)
-	    {
-	      struct netlink_res *tmpptr;
-
-	      tmpptr = nlm_next->next;
-	      free (nlm_next);
-	      nlm_next = tmpptr;
-	    }
-	  *new_nlm_list = NULL;
-
-	  if (__libc_use_alloca (2 * this_buf_size))
-	    buf = extend_alloca (buf, this_buf_size, 2 * this_buf_size);
-	  else
-	    {
-	      this_buf_size *= 2;
-
-	      char *new_buf = realloc (use_malloc ? buf : NULL, this_buf_size);
-	      if (new_buf == NULL)
-		goto out_fail;
-	      buf = new_buf;
-
-	      use_malloc = true;
-	    }
-	  buf_size = this_buf_size;
-
-	  iov.iov_base = buf;
-	  iov.iov_len = this_buf_size;
-
-	  /* Increase sequence number, so that we can distinguish
-	     between old and new request messages.  */
-	  h->seq++;
-
-	  if (__netlink_sendreq (h, type) < 0)
-	    goto out_fail;
-
-	  continue;
-	}
+	return -1;
 
       size_t count = 0;
       size_t remaining_len = read_len;
@@ -237,39 +176,9 @@ __netlink_request (struct netlink_handle
 	      struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nlmh);
 	      if (nlmh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
 		errno = EIO;
-	      else if (nlerr->error == -EBUSY
-		       && orig_this_buf_size != this_buf_size)
-		{
-		  /* If EBUSY and MSG_TRUNC was seen, try again with a new
-		     netlink socket.  */
-		  struct netlink_handle hold = *h;
-		  if (__netlink_open (h) < 0)
-		    {
-		      *h = hold;
-		      goto out_fail;
-		    }
-		  __netlink_close (&hold);
-		  orig_this_buf_size = this_buf_size;
-		  nlm_next = *new_nlm_list;
-		  while (nlm_next != NULL)
-		    {
-		      struct netlink_res *tmpptr;
-
-		      tmpptr = nlm_next->next;
-		      free (nlm_next);
-		      nlm_next = tmpptr;
-		    }
-		  *new_nlm_list = NULL;
-		  count = 0;
-		  h->seq++;
-
-		  if (__netlink_sendreq (h, type) < 0)
-		    goto out_fail;
-		  break;
-		}
 	      else
 		errno = -nlerr->error;
-	      goto out_fail;
+	      return -1;
 	    }
 	}
 
@@ -281,7 +190,7 @@ __netlink_request (struct netlink_handle
       nlm_next = (struct netlink_res *) malloc (sizeof (struct netlink_res)
 						+ read_len);
       if (nlm_next == NULL)
-	goto out_fail;
+	return -1;
       nlm_next->next = NULL;
       nlm_next->nlh = memcpy (nlm_next + 1, buf, read_len);
       nlm_next->size = read_len;
@@ -293,14 +202,7 @@ __netlink_request (struct netlink_handle
       h->end_ptr = nlm_next;
     }
 
-  if (use_malloc)
-    free (buf);
   return 0;
-
-out_fail:
-  if (use_malloc)
-    free (buf);
-  return -1;
 }
 
 

	Jakub

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Better fix for ifaddrs
  2007-03-14 18:16 [PATCH] Better fix for ifaddrs Jakub Jelinek
@ 2007-03-15  0:45 ` Ulrich Drepper
  2007-03-15  8:37   ` Jakub Jelinek
  0 siblings, 1 reply; 3+ messages in thread
From: Ulrich Drepper @ 2007-03-15  0:45 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Glibc hackers

[-- Attachment #1: Type: text/plain, Size: 411 bytes --]

Jakub Jelinek wrote:
> if you think I should use
> __libc_use_alloca even for this, please let me know.

I fear for archs like ia64 and ppc64 where the page size can widely vary
we need this.  But I think that this code should be optional, i.e., only
for those archs.  No need to slow down the rest of the world.

-- 
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 251 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Better fix for ifaddrs
  2007-03-15  0:45 ` Ulrich Drepper
@ 2007-03-15  8:37   ` Jakub Jelinek
  0 siblings, 0 replies; 3+ messages in thread
From: Jakub Jelinek @ 2007-03-15  8:37 UTC (permalink / raw)
  To: Ulrich Drepper; +Cc: Glibc hackers

On Wed, Mar 14, 2007 at 05:45:15PM -0700, Ulrich Drepper wrote:
> Jakub Jelinek wrote:
> > if you think I should use
> > __libc_use_alloca even for this, please let me know.
> 
> I fear for archs like ia64 and ppc64 where the page size can widely vary
> we need this.  But I think that this code should be optional, i.e., only
> for those archs.  No need to slow down the rest of the world.

Ok, how about this then?

On x86_64/i386 where PAGE_SIZE is defined, constant and <= PTHREAD_STACK_MIN/4 
the malloc+free are completely optimized out by the compiler, the only bad
thing there is that it will still use char *buf = alloca (4096); rather than
char buf[4096]; which is a few instructions more expensive.  But even that
is fixable in the compiler (if alloca with a constant argument is always
reachable from the entry BB, then the compiler can just create a char array
with that size instead of alloca).  Working around this in glibc would be
ugly, hardcoding what __libc_use_alloca does internally e.g. in preprocessor
directive would be bad.

2007-03-15  Jakub Jelinek  <jakub@redhat.com>

	* sysdeps/unix/sysv/linux/ifaddrs.c (__netlink_request): Never reallocate
	the buffer, instead fail for MSG_TRUNC or for EBUSY NLMSG_ERR.  Instead
	use a page sized buffer.
	* sysdeps/unix/sysv/linux/check_pf.c (make_request): Use page sized
	buffer.

--- libc/sysdeps/unix/sysv/linux/check_pf.c.jj	2007-01-03 11:04:37.000000000 +0100
+++ libc/sysdeps/unix/sysv/linux/check_pf.c	2007-03-15 09:20:11.000000000 +0100
@@ -1,5 +1,5 @@
 /* Determine protocol families for which interfaces exist.  Linux version.
-   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -71,17 +71,38 @@ make_request (int fd, pid_t pid, bool *s
   memset (&nladdr, '\0', sizeof (nladdr));
   nladdr.nl_family = AF_NETLINK;
 
+#ifdef PAGE_SIZE
+  /* Help the compiler optimize out the malloc call if PAGE_SIZE
+     is constant and smaller or equal to PTHREAD_STACK_MIN/4.  */
+  const size_t buf_size = PAGE_SIZE;
+#else
+  const size_t buf_size = __getpagesize ();
+#endif
+  bool use_malloc = false;
+  char *buf;
+
+  if (__libc_use_alloca (buf_size))
+    buf = alloca (buf_size);
+  else
+    {
+      buf = malloc (buf_size);
+      if (buf != NULL)
+	use_malloc = true;
+      else
+	goto out_fail;
+    }
+
+  struct iovec iov = { buf, buf_size };
+
   if (TEMP_FAILURE_RETRY (__sendto (fd, (void *) &req, sizeof (req), 0,
 				    (struct sockaddr *) &nladdr,
 				    sizeof (nladdr))) < 0)
-    return -1;
+    goto out_fail;
 
   *seen_ipv4 = false;
   *seen_ipv6 = false;
 
   bool done = false;
-  char buf[4096];
-  struct iovec iov = { buf, sizeof (buf) };
   struct in6ailist
   {
     struct in6addrinfo info;
@@ -101,10 +122,10 @@ make_request (int fd, pid_t pid, bool *s
 
       ssize_t read_len = TEMP_FAILURE_RETRY (__recvmsg (fd, &msg, 0));
       if (read_len < 0)
-	return -1;
+	goto out_fail;
 
       if (msg.msg_flags & MSG_TRUNC)
-	return -1;
+	goto out_fail;
 
       struct nlmsghdr *nlmh;
       for (nlmh = (struct nlmsghdr *) buf;
@@ -186,7 +207,7 @@ make_request (int fd, pid_t pid, bool *s
     {
       *in6ai = malloc (in6ailistlen * sizeof (**in6ai));
       if (*in6ai == NULL)
-	return -1;
+	goto out_fail;
 
       *in6ailen = in6ailistlen;
 
@@ -198,6 +219,13 @@ make_request (int fd, pid_t pid, bool *s
       while (in6ailist != NULL);
     }
 
+  if (use_malloc)
+    free (buf);
+  return 0;
+
+out_fail:
+  if (use_malloc)
+    free (buf);
   return 0;
 }
 
--- libc/sysdeps/unix/sysv/linux/ifaddrs.c.jj	2007-03-13 17:42:17.000000000 +0100
+++ libc/sysdeps/unix/sysv/linux/ifaddrs.c	2007-03-15 09:18:43.000000000 +0100
@@ -122,37 +122,36 @@ int
 __netlink_request (struct netlink_handle *h, int type)
 {
   struct netlink_res *nlm_next;
-  struct netlink_res **new_nlm_list;
-  static volatile size_t buf_size = 4096;
-  char *buf;
   struct sockaddr_nl nladdr;
   struct nlmsghdr *nlmh;
   ssize_t read_len;
   bool done = false;
-  bool use_malloc = false;
 
-  if (__netlink_sendreq (h, type) < 0)
-    return -1;
+#ifdef PAGE_SIZE
+  /* Help the compiler optimize out the malloc call if PAGE_SIZE
+     is constant and smaller or equal to PTHREAD_STACK_MIN/4.  */
+  const size_t buf_size = PAGE_SIZE;
+#else
+  const size_t buf_size = __getpagesize ();
+#endif
+  bool use_malloc = false;
+  char *buf;
 
-  size_t this_buf_size = buf_size;
-  size_t orig_this_buf_size = this_buf_size;
-  if (__libc_use_alloca (this_buf_size))
-    buf = alloca (this_buf_size);
+  if (__libc_use_alloca (buf_size))
+    buf = alloca (buf_size);
   else
     {
-      buf = malloc (this_buf_size);
+      buf = malloc (buf_size);
       if (buf != NULL)
 	use_malloc = true;
       else
 	goto out_fail;
     }
 
-  struct iovec iov = { buf, this_buf_size };
+  struct iovec iov = { buf, buf_size };
 
-  if (h->nlm_list != NULL)
-    new_nlm_list = &h->end_ptr->next;
-  else
-    new_nlm_list = &h->nlm_list;
+  if (__netlink_sendreq (h, type) < 0)
+    goto out_fail;
 
   while (! done)
     {
@@ -172,48 +171,7 @@ __netlink_request (struct netlink_handle
 	continue;
 
       if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0))
-	{
-	  if (this_buf_size >= SIZE_MAX / 2)
-	    goto out_fail;
-
-	  nlm_next = *new_nlm_list;
-	  while (nlm_next != NULL)
-	    {
-	      struct netlink_res *tmpptr;
-
-	      tmpptr = nlm_next->next;
-	      free (nlm_next);
-	      nlm_next = tmpptr;
-	    }
-	  *new_nlm_list = NULL;
-
-	  if (__libc_use_alloca (2 * this_buf_size))
-	    buf = extend_alloca (buf, this_buf_size, 2 * this_buf_size);
-	  else
-	    {
-	      this_buf_size *= 2;
-
-	      char *new_buf = realloc (use_malloc ? buf : NULL, this_buf_size);
-	      if (new_buf == NULL)
-		goto out_fail;
-	      buf = new_buf;
-
-	      use_malloc = true;
-	    }
-	  buf_size = this_buf_size;
-
-	  iov.iov_base = buf;
-	  iov.iov_len = this_buf_size;
-
-	  /* Increase sequence number, so that we can distinguish
-	     between old and new request messages.  */
-	  h->seq++;
-
-	  if (__netlink_sendreq (h, type) < 0)
-	    goto out_fail;
-
-	  continue;
-	}
+	goto out_fail;
 
       size_t count = 0;
       size_t remaining_len = read_len;
@@ -237,36 +195,6 @@ __netlink_request (struct netlink_handle
 	      struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nlmh);
 	      if (nlmh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
 		errno = EIO;
-	      else if (nlerr->error == -EBUSY
-		       && orig_this_buf_size != this_buf_size)
-		{
-		  /* If EBUSY and MSG_TRUNC was seen, try again with a new
-		     netlink socket.  */
-		  struct netlink_handle hold = *h;
-		  if (__netlink_open (h) < 0)
-		    {
-		      *h = hold;
-		      goto out_fail;
-		    }
-		  __netlink_close (&hold);
-		  orig_this_buf_size = this_buf_size;
-		  nlm_next = *new_nlm_list;
-		  while (nlm_next != NULL)
-		    {
-		      struct netlink_res *tmpptr;
-
-		      tmpptr = nlm_next->next;
-		      free (nlm_next);
-		      nlm_next = tmpptr;
-		    }
-		  *new_nlm_list = NULL;
-		  count = 0;
-		  h->seq++;
-
-		  if (__netlink_sendreq (h, type) < 0)
-		    goto out_fail;
-		  break;
-		}
 	      else
 		errno = -nlerr->error;
 	      goto out_fail;


	Jakub

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2007-03-15  8:37 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-03-14 18:16 [PATCH] Better fix for ifaddrs Jakub Jelinek
2007-03-15  0:45 ` Ulrich Drepper
2007-03-15  8:37   ` Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).