aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/drivers/common/efile_drv.c68
-rw-r--r--erts/emulator/drivers/common/erl_efile.h15
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c2
3 files changed, 69 insertions, 16 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index 1f13a65350..7eaafd5af1 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -358,15 +358,6 @@ struct t_readdir_buf {
char buf[READDIR_BUFSIZE];
};
-#ifdef HAVE_SENDFILE
-struct t_sendfile_hdtl {
- int hdr_cnt; /* number of header iovecs */
- struct iovec *headers; /* pointer to header iovecs */
- int trl_cnt; /* number of trailer iovecs */
- struct iovec *trailers; /* pointer to trailer iovecs */
-};
-#endif /* HAVE_SENDFILE */
-
struct t_data
{
struct t_data *next;
@@ -530,6 +521,8 @@ static void *ef_safe_realloc(void *op, Uint s)
!0) \
: 0)
+/* int EV_GET_SYSIOVEC(ErlIoVec *ev, Uint32, int *cnt, SysIOVec **target, int *pp, int *qp) */
+#define EV_GET_SYSIOVEC ev_get_sysiovec
#if 0
@@ -943,6 +936,41 @@ static int reply_eof(file_descriptor *desc) {
return 0;
}
+static int ev_get_sysiovec(ErlIOVec *ev, Uint32 len, int *cnt, SysIOVec **target, int *pp, int *qp) {
+ int tmp_p = *pp, tmp_q = *qp, tmp_len = len, i;
+ SysIOVec *tmp_target;
+ while (tmp_len != 0) {
+ if (tmp_len + tmp_p > ev->iov[tmp_q].iov_len) {
+
+ tmp_len -= ev->iov[tmp_q].iov_len - tmp_p;
+ tmp_q++;
+ tmp_p = 0;
+ if (tmp_q == ev->vsize)
+ return 0;
+ } else break;
+ }
+ *cnt = tmp_q - *qp + 1;
+ tmp_target = EF_SAFE_ALLOC(sizeof(SysIOVec)* (*cnt));
+ *target = tmp_target;
+ for (i = 0; i < *cnt; i++) {
+ tmp_target[i].iov_base = ev->iov[*qp].iov_base+*pp;
+ if (len + *pp <= ev->iov[*qp].iov_len) {
+ tmp_target[i].iov_len = len;
+ if (len + *pp == ev->iov[*qp].iov_len) {
+ *pp = 0;
+ (*qp)++;
+ } else
+ *pp += len;
+ } else {
+ tmp_target[i].iov_len = ev->iov[*qp].iov_len - *pp;
+ len -= ev->iov[*qp].iov_len - *pp;
+ *pp = 0;
+ (*qp)++;
+ }
+ }
+ return 1;
+}
+
static void invoke_name(void *data, int (*f)(Efile_error *, char *))
@@ -1753,7 +1781,7 @@ static void invoke_sendfile(void *data)
int result = 0;
d->again = 0;
- result = efile_sendfile(&d->errInfo, fd, out_fd, &d->c.sendfile.offset, &nbytes);
+ result = efile_sendfile(&d->errInfo, fd, out_fd, &d->c.sendfile.offset, &nbytes, &d->c.sendfile.hdtl);
d->c.sendfile.written += nbytes;
@@ -3394,7 +3422,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
#ifdef HAVE_SENDFILE
struct t_data *d;
- Uint32 out_fd, offsetH, offsetL;
+ Uint32 out_fd, offsetH, offsetL, hd_len, tl_len;
Uint64 nbytes;
char flags;
@@ -3410,7 +3438,9 @@ 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_UINT64(ev, &nbytes, &p, &q)) {
+ || !EV_GET_UINT64(ev, &nbytes, &p, &q)
+ || !EV_GET_UINT32(ev, &hd_len, &p, &q)
+ || !EV_GET_UINT32(ev, &tl_len, &p, &q)) {
/* Buffer has wrong length to contain all the needed values */
reply_posix_error(desc, EINVAL);
goto done;
@@ -3438,8 +3468,18 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
#endif
d->c.sendfile.nbytes = nbytes;
-
- /* Do HEADER TRAILER stuff by calculating pointer places, not by copying data! */
+ if (hd_len == 0 && tl_len == 0)
+ d->c.sendfile.hdtl = NULL;
+ else {
+ d->c.sendfile.hdtl = EF_SAFE_ALLOC(sizeof(struct t_sendfile_hdtl));
+ if (!EV_GET_SYSIOVEC(ev, hd_len, &d->c.sendfile.hdtl->hdr_cnt, &d->c.sendfile.hdtl->headers, &p, &q)
+ || !EV_GET_SYSIOVEC(ev, tl_len, &d->c.sendfile.hdtl->trl_cnt, &d->c.sendfile.hdtl->trailers, &p, &q)) {
+ EF_FREE(d->c.sendfile.hdtl);
+ EF_FREE(d);
+ reply_posix_error(desc, EINVAL);
+ goto done;
+ }
+ }
if (sys_info.async_threads != 0) {
SET_BLOCKING(d->c.sendfile.out_fd);
diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h
index fd6dc94755..b73fb35120 100644
--- a/erts/emulator/drivers/common/erl_efile.h
+++ b/erts/emulator/drivers/common/erl_efile.h
@@ -118,6 +118,19 @@ typedef struct _Efile_info {
*/
} Efile_info;
+
+#ifdef HAVE_SENDFILE
+/*
+ * Described the structure of header/trailers for sendfile
+ */
+struct t_sendfile_hdtl {
+ SysIOVec *headers;
+ int hdr_cnt;
+ SysIOVec *trailers;
+ int trl_cnt;
+};
+#endif /* HAVE_SENDFILE */
+
/*
* Functions.
*/
@@ -164,5 +177,5 @@ int efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length,
int advise);
#ifdef HAVE_SENDFILE
int efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
- off_t *offset, Uint64 *nbytes);
+ off_t *offset, Uint64 *nbytes, struct t_sendfile_hdtl **hdtl);
#endif /* HAVE_SENDFILE */
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 01de088b0f..138c550fdd 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -1473,7 +1473,7 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
int
efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
- off_t *offset, Uint64 *nbytes)
+ off_t *offset, Uint64 *nbytes, struct t_sendfile_hdtl** hdtl)
{
Uint64 written = 0;
#if defined(__linux__) || (defined(__sun) && defined(__SVR4))