net: fix unnoticed short reads

This commit is contained in:
Thomas Schoebel-Theuer 2014-11-25 13:06:52 +01:00
parent aa09d7df30
commit 039858ae30
1 changed files with 29 additions and 6 deletions

View File

@ -515,7 +515,20 @@ final:
} }
EXPORT_SYMBOL_GPL(mars_send_raw); EXPORT_SYMBOL_GPL(mars_send_raw);
/* Note: buf may be NULL. In this case, the data is simply consumed, /**
* mars_recv_raw() - Get [min,max] number of bytes
* @msock: socket to read from
* @buf: buffer to put the data in
* @minlen: minimum number of bytes to read
* @maxlen: maximum number of bytes to read
*
* Returns a negative error code or a number between [@minlen,@maxlen].
* Short reads are mapped to an error.
*
* Hint: by setting @minlen to 1, you can read any number up to @maxlen.
* However, the most important use case is @minlen == @maxlen.
*
* Note: buf may be NULL. In this case, the data is simply consumed,
* like /dev/null * like /dev/null
*/ */
int mars_recv_raw(struct mars_socket *msock, void *buf, int minlen, int maxlen) int mars_recv_raw(struct mars_socket *msock, void *buf, int minlen, int maxlen)
@ -536,10 +549,20 @@ int mars_recv_raw(struct mars_socket *msock, void *buf, int minlen, int maxlen)
if (!mars_get_socket(msock)) if (!mars_get_socket(msock))
goto final; goto final;
if (minlen < maxlen) {
struct socket *sock = msock->s_socket;
if (sock && sock->file) {
/* Use nonblocking reads to consume as much data
* as possible
*/
sock->file->f_flags |= O_NONBLOCK;
}
}
MARS_IO("#%d receiving len=%d/%d bytes\n", msock->s_debug_nr, minlen, maxlen); MARS_IO("#%d receiving len=%d/%d bytes\n", msock->s_debug_nr, minlen, maxlen);
msock->s_recv_cnt = 0; msock->s_recv_cnt = 0;
while (done < minlen) { while (done < minlen || (!minlen && !done)) {
struct kvec iov = { struct kvec iov = {
.iov_base = buf + done, .iov_base = buf + done,
.iov_len = maxlen - done, .iov_len = maxlen - done,
@ -559,7 +582,6 @@ int mars_recv_raw(struct mars_socket *msock, void *buf, int minlen, int maxlen)
if (!mars_net_is_alive || brick_thread_should_stop()) { if (!mars_net_is_alive || brick_thread_should_stop()) {
MARS_WRN("#%d interrupting, done = %d\n", msock->s_debug_nr, done); MARS_WRN("#%d interrupting, done = %d\n", msock->s_debug_nr, done);
if (done > 0)
status = -EIDRM; status = -EIDRM;
goto err; goto err;
} }
@ -572,7 +594,6 @@ int mars_recv_raw(struct mars_socket *msock, void *buf, int minlen, int maxlen)
if (!mars_net_is_alive || brick_thread_should_stop()) { if (!mars_net_is_alive || brick_thread_should_stop()) {
MARS_WRN("#%d interrupting, done = %d\n", msock->s_debug_nr, done); MARS_WRN("#%d interrupting, done = %d\n", msock->s_debug_nr, done);
if (done > 0)
status = -EIDRM; status = -EIDRM;
goto err; goto err;
} }
@ -584,6 +605,8 @@ int mars_recv_raw(struct mars_socket *msock, void *buf, int minlen, int maxlen)
goto err; goto err;
} }
brick_msleep(sleeptime); brick_msleep(sleeptime);
if (minlen <= 0)
break;
// linearly increasing backoff // linearly increasing backoff
if (sleeptime < 100) { if (sleeptime < 100) {
sleeptime += 1000 / HZ; sleeptime += 1000 / HZ;