libulockmgr: Work around a kernel bug in recv()
authorMiklos Szeredi <miklos@szeredi.hu>
Sun, 3 Jun 2007 08:30:42 +0000 (08:30 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Sun, 3 Jun 2007 08:30:42 +0000 (08:30 +0000)
ChangeLog
lib/ulockmgr.c
util/ulockmgr_server.c

index 570a36f00b47000e5d9b316ea643c4440334c44b..9e8a830861fc57734e130bbe2697937359ce5ab6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2007-06-03  Miklos Szeredi <miklos@szeredi.hu>
+
+       * libulockmgr: Work around a kernel bug in recv(), causing it to
+       sometimes return zero even if data was available on the socket.
+
 2007-05-29  Miklos Szeredi <miklos@szeredi.hu>
 
        * lib: optimization: store parent pointer in node instead of
index bf27b36a8b6a916965b281092134d424e9111a45..05b940f56402e4900bbca385c75d1e5330c20bc9 100644 (file)
@@ -69,6 +69,21 @@ static void list_add_owner(struct owner *owner, struct owner *next)
     next->prev = owner;
 }
 
+/*
+ * There's a bug in the linux kernel (< 2.6.22) recv() implementation
+ * on AF_UNIX, SOCK_STREAM sockets, that could cause it to return
+ * zero, even if data was available.  Retrying the recv will return
+ * the data in this case.
+*/
+static int do_recv(int sock, void *buf, size_t len, int flags)
+{
+    int res = recv(sock, buf, len, flags);
+    if (res == 0)
+        res = recv(sock, buf, len, flags);
+
+    return res;
+}
+
 static int ulockmgr_send_message(int sock, void *buf, size_t buflen,
                                  int *fdp, int numfds)
 {
@@ -252,7 +267,7 @@ static int ulockmgr_send_request(struct message *msg, const void *id,
     if (f)
         f->inuse++;
 
-    res = recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
+    res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
     if (res == -1) {
         perror("libulockmgr: recv");
         msg->error = EIO;
@@ -269,7 +284,7 @@ static int ulockmgr_send_request(struct message *msg, const void *id,
             sigemptyset(&unblock);
             sigaddset(&unblock, SIGUSR1);
             pthread_sigmask(SIG_UNBLOCK, &unblock, &old);
-            res = recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
+            res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
             errno_save = errno;
             pthread_sigmask(SIG_SETMASK, &old, NULL);
             if (res == sizeof(struct message))
index 211d74ace30dc9b80b5575e99c0835e4153e4b73..4f831b041293082004e2f5a28d90d1428e0eab03 100644 (file)
@@ -75,8 +75,12 @@ static int receive_message(int sock, void *buf, size_t buflen, int *fdp,
     msg.msg_controllen = sizeof(ccmsg);
 
     res = recvmsg(sock, &msg, MSG_WAITALL);
-    if (!res)
-        return 0;
+    if (!res) {
+        /* retry on zero return, see do_recv() in ulockmgr.c */
+        res = recvmsg(sock, &msg, MSG_WAITALL);
+        if (!res)
+            return 0;
+    }
     if (res == -1) {
         perror("ulockmgr_server: recvmsg");
         return -1;