aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--lib/ulockmgr.c19
-rw-r--r--util/ulockmgr_server.c8
3 files changed, 28 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 570a36f..9e8a830 100644
--- 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
diff --git a/lib/ulockmgr.c b/lib/ulockmgr.c
index bf27b36..05b940f 100644
--- a/lib/ulockmgr.c
+++ b/lib/ulockmgr.c
@@ -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))
diff --git a/util/ulockmgr_server.c b/util/ulockmgr_server.c
index 211d74a..4f831b0 100644
--- a/util/ulockmgr_server.c
+++ b/util/ulockmgr_server.c
@@ -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;