[erlang-patches] [PATCH] erts: fix error logic in efile_sendfile
Michael Santos
michael.santos@REDACTED
Tue Dec 6 17:57:55 CET 2011
On Tue, Dec 06, 2011 at 05:49:51PM +0800, Jovi Zhang wrote:
> On Tue, Dec 6, 2011 at 4:51 PM, Henrik Nord <henrik@REDACTED> wrote:
> > Hello!
> >
> > We can not get the tests to pass with this patch.
> > can you rerun the test at your side and verify that they all pass?
> >
> > Thank you
> >
>
> Sorry, I missed that "*nbytes == 0" have special meaning used by upper layer.
> I will take more carefully in next time.
>
> I have removed "*nbytes == 0" part, please try below new patch.
>
>
> From cbfce8104b708e7df287b88783bf7bdc21dc1035 Mon Sep 17 00:00:00 2001
> From: Jovi Zhang <bookjovi@REDACTED>
> Date: Tue, 29 Nov 2011 05:23:56 +0800
> Subject: [PATCH] erts: minor fix for unnecessary condition
>
> In "while (retval != -1 && retval == SENDFILE_CHUNK_SIZE)", "retval !=
> -1" is pointless.
- } while (retval != -1 && retval == SENDFILE_CHUNK_SIZE);
+ } while (retval == SENDFILE_CHUNK_SIZE);
Looks ok, but the surrounding code looks sketchy.
For Linux:
erts/emulator/drivers/unix/unix_efile.c:
do {
// check if *nbytes is 0 or greater than the largest size_t
if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE)
retval = sendfile(out_fd, in_fd, offset, SENDFILE_CHUNK_SIZE);
else
retval = sendfile(out_fd, in_fd, offset, *nbytes);
if (retval > 0) {
written += retval;
*nbytes -= retval;
}
} while (retval != -1 && retval == SENDFILE_CHUNK_SIZE);
*nbytes = written;
return check_error(retval == -1 ? -1 : 0, errInfo);
Note the ternary check in check_error() is not required either:
return check_error(retval, errInfo);
On error, sendfile returns -1 and sets errno. So the function will
return on error, including EAGAIN and EINTR.
The calling function, invoke_sendfile(), ignores EAGAIN and EINTR:
erts/emulator/drivers/common/efile_drv.c:
} else if (result == 0 && (d->errInfo.posix_errno == EAGAIN
|| d->errInfo.posix_errno == EINTR)) {
d->result_ok = 1;
}
For Darwin:
erts/emulator/drivers/unix/unix_efile.c:
int retval;
off_t len;
do {
// check if *nbytes is 0 or greater than the largest off_t
if(*nbytes > SENDFILE_CHUNK_SIZE)
len = SENDFILE_CHUNK_SIZE;
else
len = *nbytes;
retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0);
if (retval != -1 || errno == EAGAIN || errno == EINTR) {
*offset += len;
*nbytes -= len;
written += len;
}
} while (len == SENDFILE_CHUNK_SIZE);
*nbytes = written;
return check_error(retval, errInfo);
If retval returns an error and errno is either EAGAIN or EINTR, the
chunk is discarded and the offset moved to the next chunk. Probably the
check should be:
if (retval != -1) {
In the case where len is set to SENDFILE_CHUNK_SIZE and sendfile returns
an error other than EAGAIN/EINTR (for example, the fd is bad, etc),
the driver will go into a loop.
For FreeBSD:
The code is similar to Darwin, so the same changes need to be applied.
More information about the erlang-patches
mailing list