__readall() and __readvall() in nscd/nscd_helper.c

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

__readall() and __readvall() in nscd/nscd_helper.c

mdm-2
Hi all,

When nscd has a sufficiently large reply to a query (for instance a group
with many members), the entire reply may not yet be ready for reading in
the client when it first returns from __poll() indicating that the socket
is ready for reading. The functions __readall() and __readvall() in
nscd/nscd_helper.c expect that the entire reply can be read immediately,
since __poll() indicated that the socket was ready, but in reality this is
not always the case - nscd may need to get scheduled again before more
data will be available.

The effect of this problem is that when using nscd, calls to functions
like getgrgid() may fail intermittently when the reply is large. The
attached patch adds calls to __poll() inside the loops in these two
functions when errno is EAGAIN to correct the problem.

Mike Mammarella


nscd-client.patch.gz (750 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [patch] __readall() and __readvall() in nscd/nscd_helper.c

mdm-2
In case the patch being an attachment is a problem, here it is in the
message:

> Hi all,
>
> When nscd has a sufficiently large reply to a query (for instance a group
> with many members), the entire reply may not yet be ready for reading in
> the client when it first returns from __poll() indicating that the socket
> is ready for reading. The functions __readall() and __readvall() in
> nscd/nscd_helper.c expect that the entire reply can be read immediately,
> since __poll() indicated that the socket was ready, but in reality this is
> not always the case - nscd may need to get scheduled again before more
> data will be available.
>
> The effect of this problem is that when using nscd, calls to functions
> like getgrgid() may fail intermittently when the reply is large. The
> attached patch adds calls to __poll() inside the loops in these two
> functions when errno is EAGAIN to correct the problem.
>
> Mike Mammarella

--- nscd/nscd_helper.c  2006-02-28 21:39:03.000000000 -0800
+++ nscd/nscd_helper.c  2006-09-14 16:29:45.812773000 -0700
@@ -44,6 +44,14 @@
   do
     {
       ret = TEMP_FAILURE_RETRY (__read (fd, buf, n));
+      if (ret < 0 && errno == EAGAIN)
+       {
+         struct pollfd fds[1];
+         fds[0].fd = fd;
+         fds[0].events = POLLIN | POLLERR | POLLHUP;
+         if (__poll (fds, 1, 200) > 0)
+           continue;
+       }
       if (ret <= 0)
        break;
       buf = (char *) buf + ret;
@@ -58,8 +66,10 @@
 __readvall (int fd, const struct iovec *iov, int iovcnt)
 {
   ssize_t ret = TEMP_FAILURE_RETRY (__readv (fd, iov, iovcnt));
-  if (ret <= 0)
+  if (ret <= 0 && errno != EAGAIN)
     return ret;
+  if (ret < 0)
+    ret = 0;

   size_t total = 0;
   for (int i = 0; i < iovcnt; ++i)
@@ -82,6 +92,17 @@
          iovp->iov_base = (char *) iovp->iov_base + r;
          iovp->iov_len -= r;
          r = TEMP_FAILURE_RETRY (__readv (fd, iovp, iovcnt));
+         if (r < 0 && errno == EAGAIN)
+           {
+             struct pollfd fds[1];
+             fds[0].fd = fd;
+             fds[0].events = POLLIN | POLLERR | POLLHUP;
+             if (__poll (fds, 1, 200) > 0)
+               {
+                 r = 0;
+                 continue;
+               }
+           }
          if (r <= 0)
            break;
          ret += r;