From 966b4ec5e5cc2a6f49b7559461eb99a61e9ec227 Mon Sep 17 00:00:00 2001 From: Aaron Myers Date: Fri, 17 May 2013 00:11:11 +0000 Subject: [PATCH] HADOOP-9566. Performing direct read using libhdfs sometimes raises SIGPIPE (which in turn throws SIGABRT) causing client crashes. Contributed by Colin Patrick McCabe. git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1483613 13f79535-47bb-0310-9956-ffa450edef68 --- .../hadoop-common/CHANGES.txt | 4 +++ .../org/apache/hadoop/net/unix/DomainSocket.c | 30 ++++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index 36526b3cf3b..0f659b54b09 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -185,6 +185,10 @@ Release 2.0.5-beta - UNRELEASED HADOOP-9563. Fix incompatibility introduced by HADOOP-9523. (Tian Hong Wang via suresh) + HADOOP-9566. Performing direct read using libhdfs sometimes raises SIGPIPE + (which in turn throws SIGABRT) causing client crashes. (Colin Patrick + McCabe via atm) + Release 2.0.4-alpha - 2013-04-25 INCOMPATIBLE CHANGES diff --git a/hadoop-common-project/hadoop-common/src/main/native/src/org/apache/hadoop/net/unix/DomainSocket.c b/hadoop-common-project/hadoop-common/src/main/native/src/org/apache/hadoop/net/unix/DomainSocket.c index 1c2ea698a00..cf34c525323 100644 --- a/hadoop-common-project/hadoop-common/src/main/native/src/org/apache/hadoop/net/unix/DomainSocket.c +++ b/hadoop-common-project/hadoop-common/src/main/native/src/org/apache/hadoop/net/unix/DomainSocket.c @@ -16,8 +16,7 @@ * limitations under the License. */ -#define _GNU_SOURCE - +#include "config.h" #include "exception.h" #include "org/apache/hadoop/io/nativeio/file_descriptor.h" #include "org_apache_hadoop.h" @@ -31,6 +30,7 @@ #include #include #include +#include #include /* for FIONREAD */ #include #include @@ -47,6 +47,15 @@ #define DEFAULT_SEND_TIMEOUT 120000 #define LISTEN_BACKLOG 128 +/* In Linux, you can pass the MSG_NOSIGNAL flag to send, sendto, etc. to prevent + * those functions from generating SIGPIPE. HDFS-4831 for details. + */ +#ifdef MSG_NOSIGNAL +#define PLATFORM_SEND_FLAGS MSG_NOSIGNAL +#else +#define PLATFORM_SEND_FLAGS 0 +#endif + /** * Can't pass more than this number of file descriptors in a single message. */ @@ -176,6 +185,19 @@ static jthrowable setup(JNIEnv *env, int *ofd, jobject jpath, int doConnect) "is %zd bytes.", sizeof(addr.sun_path) - 1); goto done; } +#ifdef SO_NOSIGPIPE + /* On MacOS and some BSDs, SO_NOSIGPIPE will keep send and sendto from causing + * EPIPE. Note: this will NOT help when using write or writev, only with + * send, sendto, sendmsg, etc. See HDFS-4831. + */ + ret = 1; + if (setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&ret, sizeof(ret))) { + ret = errno; + jthr = newSocketException(env, ret, + "error setting SO_NOSIGPIPE on socket: error %s", terror(ret)); + goto done; + } +#endif if (doConnect) { RETRY_ON_EINTR(ret, connect(fd, (struct sockaddr*)&addr, sizeof(addr))); @@ -583,7 +605,7 @@ static jthrowable write_fully(JNIEnv *env, int fd, int8_t *buf, int amt) int err, res; while (amt > 0) { - res = write(fd, buf, amt); + res = send(fd, buf, amt, PLATFORM_SEND_FLAGS); if (res < 0) { err = errno; if (err == EINTR) { @@ -685,7 +707,7 @@ jint offset, jint length) goto done; } } - RETRY_ON_EINTR(ret, sendmsg(fd, &socketMsg, 0)); + RETRY_ON_EINTR(ret, sendmsg(fd, &socketMsg, PLATFORM_SEND_FLAGS)); if (ret < 0) { ret = errno; jthr = newSocketException(env, ret, "sendmsg(2) error: %s", terror(ret));