about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--sysdeps/unix/sysv/linux/ifaddrs.c31
2 files changed, 37 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 8fbcb8b133..6256913526 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2007-03-02  Jakub Jelinek  <jakub@redhat.com>
+
+	* sysdeps/unix/sysv/linux/ifaddrs.c (__netlink_request): Retry with
+	a new netlink socket if NLMSG_ERR -EBUSY is seen after some MSG_TRUNC
+	message.
+
 2007-03-01  Jakub Jelinek  <jakub@redhat.com>
 
 	[BZ #4069]
diff --git a/sysdeps/unix/sysv/linux/ifaddrs.c b/sysdeps/unix/sysv/linux/ifaddrs.c
index e43f39f9e3..6c0f6b3dce 100644
--- a/sysdeps/unix/sysv/linux/ifaddrs.c
+++ b/sysdeps/unix/sysv/linux/ifaddrs.c
@@ -135,6 +135,7 @@ __netlink_request (struct netlink_handle *h, int type)
     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
@@ -236,6 +237,36 @@ __netlink_request (struct netlink_handle *h, int type)
 	      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;