diff options
author | Eric Wong <e@yhbt.net> | 2013-07-31 20:26:25 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2013-08-22 19:28:12 +0000 |
commit | 1199492dd1adb394cf4cc0d599e7f77c52ccbdbf (patch) | |
tree | 4288bc3f99854c0ca8839d4c2433cd6dda410aaf /trywrite.c | |
parent | 317b979e29774a77fb933c4f42514ff007669b39 (diff) | |
download | cmogstored-1199492dd1adb394cf4cc0d599e7f77c52ccbdbf.tar.gz |
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.
Diffstat (limited to 'trywrite.c')
-rw-r--r-- | trywrite.c | 34 |
1 files changed, 23 insertions, 11 deletions
@@ -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; |