From 1199492dd1adb394cf4cc0d599e7f77c52ccbdbf Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 31 Jul 2013 20:26:25 +0000 Subject: trywrite: workaround potential inf loops from kernel bugs While we're fortunate enough to not have encountered a case where send/writev returns zero with a non-zero-length buffer, it's not inconceivable that it could strike us one day. In that case, error out the connection instead of infinite looping. Dropping a connection is safer than letting a thread run in an infinite loop. --- trywrite.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/trywrite.c b/trywrite.c index 7078748..1325e8c 100644 --- a/trywrite.c +++ b/trywrite.c @@ -35,6 +35,11 @@ static void * wbuf_new(void *buf, size_t len) return wbuf_newv(len, &iov, 1); } +MOG_NOINLINE static void sysbug(const char *fn, ssize_t bytes) +{ + syslog(LOG_ERR, "%s returned %zd bytes written but: %m", fn, bytes); +} + enum mog_write_state mog_tryflush(int fd, struct mog_wbuf **x) { struct mog_wbuf *wbuf = *x; @@ -90,12 +95,13 @@ retry: if (w == len) { return NULL; - } else if (w < 0) { + } else if (w <= 0) { switch (errno) { case_EAGAIN: TRACE(CMOGSTORED_WRITE_BUFFERED()); return wbuf_newv(len, iov, iovcnt); case EINTR: goto retry; + case 0: sysbug("writev", w); } return MOG_WR_ERROR; } else { @@ -146,19 +152,25 @@ void * mog_trysend(int fd, void *buf, size_t len, off_t more) if (w == (ssize_t)len) return NULL; /* all done */ - - if (w < 0) { - switch (errno) { - case_EAGAIN: - TRACE(CMOGSTORED_WRITE_BUFFERED()); - return wbuf_new(buf, len); - case EINTR: continue; - } - return MOG_WR_ERROR; - } else { + if (w > 0) { buf = (char *)buf + w; len -= w; + continue; + } + + /* + * we bail on w == 0, too. send should normally + * return zero, but in case there's a kernel bug + * we should not infinite loop + */ + switch (errno) { + case_EAGAIN: + TRACE(CMOGSTORED_WRITE_BUFFERED()); + return wbuf_new(buf, len); + case EINTR: continue; + case 0: sysbug("send", w); } + return MOG_WR_ERROR; } return NULL; -- cgit v1.2.3-24-ge0c7