aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/drivers/common/efile_drv.c26
-rw-r--r--erts/emulator/drivers/common/erl_efile.h2
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c53
3 files changed, 44 insertions, 37 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index 98da63f4e3..5d785a75c4 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -421,7 +421,7 @@ struct t_data
struct {
int out_fd;
off_t offset;
- size_t nbytes;
+ Uint64 nbytes;
Uint64 written;
short flags;
struct t_sendfile_hdtl *hdtl;
@@ -1728,7 +1728,7 @@ static void invoke_sendfile(void *data)
struct t_data *d = (struct t_data *)data;
int fd = d->fd;
int out_fd = d->c.sendfile.out_fd;
- size_t nbytes = d->c.sendfile.nbytes;
+ Uint64 nbytes = d->c.sendfile.nbytes;
int result = 0;
d->again = 0;
@@ -2197,12 +2197,13 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
free_preadv(data);
break;
case FILE_SENDFILE:
- printf("efile_ready_async: sendfile (d->result_ok == %d)\r\n",d->result_ok);
+ //printf("efile_ready_async: sendfile (d->result_ok == %d)\r\n",d->result_ok);
if (d->result_ok == -1) {
desc->sendfile_state = not_sending;
reply_error(desc, &d->errInfo);
if (sys_info.async_threads != 0) {
SET_NONBLOCKING(d->c.sendfile.out_fd);
+ free_sendfile(data);
} else {
driver_select(desc->port, (ErlDrvEvent)d->c.sendfile.out_fd,
ERL_DRV_USE, 0);
@@ -2212,6 +2213,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
reply_Sint64(desc, d->c.sendfile.written);
if (sys_info.async_threads != 0) {
SET_NONBLOCKING(d->c.sendfile.out_fd);
+ free_sendfile(data);
} else {
driver_select(desc->port, (ErlDrvEvent)d->c.sendfile.out_fd,
ERL_DRV_USE, 0);
@@ -3367,7 +3369,8 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
case FILE_SENDFILE: {
struct t_data *d;
- Uint32 out_fd, offsetH, offsetL, nbytesH, nbytesL;
+ Uint32 out_fd, offsetH, offsetL;
+ Uint64 nbytes;
char flags;
/* DestFD:32, Offset:64, Bytes:64,
@@ -3382,8 +3385,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
|| !EV_GET_CHAR(ev, &flags, &p, &q)
|| !EV_GET_UINT32(ev, &offsetH, &p, &q)
|| !EV_GET_UINT32(ev, &offsetL, &p, &q)
- || !EV_GET_UINT32(ev, &nbytesH, &p, &q)
- || !EV_GET_UINT32(ev, &nbytesL, &p, &q)) {
+ || !EV_GET_UINT64(ev, &nbytes, &p, &q)) {
/* Buffer has wrong length to contain all the needed values */
reply_posix_error(desc, EINVAL);
goto done;
@@ -3410,17 +3412,9 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
d->c.sendfile.offset = ((off_t) offsetH << 32) | offsetL;
#endif
- #if SIZEOF_SIZE_T == 4
- if (nbytesH != 0) {
- reply_posix_error(desc, EINVAL);
- goto done;
- }
- d->c.sendfile.nbytes = (size_t) nbytesL;
- #else
- d->c.sendfile.nbytes = ((size_t) nbytesH << 32) | nbytesL;
- #endif
+ d->c.sendfile.nbytes = nbytes;
- printf("sendfile(nbytes => %d, offset => %d, flags => %x)\r\n",d->c.sendfile.nbytes,d->c.sendfile.offset, d->c.sendfile.flags);
+ printf("sendfile(nbytes => %ld, offset => %d, flags => %x)\r\n",d->c.sendfile.nbytes,d->c.sendfile.offset, d->c.sendfile.flags);
/* Do HEADER TRAILER stuff by calculating pointer places, not by copying data! */
diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h
index e0b8cfca03..8e79b3923a 100644
--- a/erts/emulator/drivers/common/erl_efile.h
+++ b/erts/emulator/drivers/common/erl_efile.h
@@ -163,4 +163,4 @@ int efile_may_openfile(Efile_error* errInfo, char *name);
int efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length,
int advise);
int efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
- off_t *offset, size_t *nbytes);
+ off_t *offset, Uint64 *nbytes);
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 61df572a91..911ec63588 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -1469,33 +1469,46 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
}
#ifdef HAVE_SENDFILE
-#define SENDFILE_CHUNK_SIZE ((1 << 30) - 1)
int
efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
- off_t *offset, size_t *nbytes)
+ off_t *offset, Uint64 *nbytes)
{
+ // printf("sendfile(%d,%d,%d,%d)\r\n",out_fd,in_fd,*offset,*nbytes);
+ Uint64 written = 0;
#if defined(__linux__) || (defined(__sun) && defined(__SVR4))
- ssize_t retval, written = 0;
- // printf("sendfile(%d,%d,%d,%d)\r\n",out_fd,in_fd,*offset,*nbytes);
- if (*nbytes == 0) {
- do {
- *nbytes = SENDFILE_CHUNK_SIZE; // chunk size
- retval = sendfile(out_fd, in_fd, offset, *nbytes);
- if (retval > 0)
- written += retval;
- } while (retval == SENDFILE_CHUNK_SIZE);
- } else {
- retval = sendfile(out_fd, in_fd, offset, *nbytes);
- if (retval > 0)
- written = retval;
- }
+#define SENDFILE_CHUNK_SIZE ((1 << (8*SIZEOF_SIZE_T)) - 1)
+ ssize_t retval;
+ 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 == SENDFILE_CHUNK_SIZE);
*nbytes = written;
return check_error(retval == -1 ? -1 : 0, errInfo);
#elif defined(DARWIN)
- off_t len = *nbytes;
- int retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0);
- *offset += len;
- *nbytes = len;
+#define SENDFILE_CHUNK_SIZE ((1 << (8*SIZEOF_OFF_T)) - 1)
+ 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);
#elif defined(__FreeBSD__) || defined(__DragonFly__)
off_t len = 0;