aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--erts/preloaded/src/prim_file.erl35
-rw-r--r--lib/kernel/src/gen_tcp.erl14
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE.erl2
6 files changed, 87 insertions, 49 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))
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index 6bdf5f6e2e..fb19521382 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -547,38 +547,21 @@ write_file(_, _) ->
sendfile(#file_descriptor{module = ?MODULE, data = {Port, _}},
DestFD, Offset, Bytes, ChunkSize, Headers, Trailers,
Nodiskio, MNowait, Sync) ->
- drv_command(Port, <<?FILE_SENDFILE, DestFD:32,
- (get_bit(Nodiskio)):1,
- (get_bit(MNowait)):1,
- (get_bit(Sync)):1,0:5,
- Offset:64/unsigned,
- Bytes:64/unsigned,
- ChunkSize:64,
- (encode_hdtl(Headers))/binary,
- (encode_hdtl(Trailers))/binary>>).
+ drv_command(Port, [<<?FILE_SENDFILE, DestFD:32,
+ (get_bit(Nodiskio)):1,
+ (get_bit(MNowait)):1,
+ (get_bit(Sync)):1,0:5,
+ Offset:64/unsigned,
+ Bytes:64/unsigned,
+ (iolist_size(Headers)):32/unsigned,
+ (iolist_size(Trailers)):32/unsigned>>,
+ Headers,Trailers]).
get_bit(true) ->
1;
get_bit(false) ->
0.
-encode_hdtl(undefined) ->
- <<0>>;
-encode_hdtl([]) ->
- <<0>>;
-encode_hdtl(List) ->
- encode_hdtl(List,<<>>,0).
-
-encode_hdtl([], Acc, Cnt) ->
- <<Cnt:8, Acc/binary>>;
-encode_hdtl([Bin|T], Acc, Cnt) when is_binary(Bin) ->
- encode_hdtl(T, <<(byte_size(Bin)):32, Bin/binary, Acc/binary>>,Cnt + 1);
-encode_hdtl([Bin|T], Acc, Cnt) ->
- encode_hdtl(T, <<(iolist_size(Bin)):32, (iolist_to_binary(Bin))/binary,
- Acc/binary>>,Cnt + 1).
-
-
-
%%%-----------------------------------------------------------------
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index 2eaa44b966..78e3ab3697 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -327,7 +327,7 @@ unrecv(S, Data) when is_port(S) ->
sendfile(File, _Sock, _Offet, _Bytes, _Opts) when is_pid(File) ->
{error, badarg};
sendfile(File, Sock, Offset, Bytes, []) ->
- sendfile(File, Sock, Offset, Bytes, ?MAX_CHUNK_SIZE, undefined, undefined,
+ sendfile(File, Sock, Offset, Bytes, ?MAX_CHUNK_SIZE, [], [],
false, false, false);
sendfile(File, Sock, Offset, Bytes, Opts) ->
ChunkSize0 = proplists:get_value(chunk_size, Opts, ?MAX_CHUNK_SIZE),
@@ -335,8 +335,8 @@ sendfile(File, Sock, Offset, Bytes, Opts) ->
?MAX_CHUNK_SIZE;
true -> ChunkSize0
end,
- Headers = proplists:get_value(headers, Opts),
- Trailers = proplists:get_value(trailers, Opts),
+ Headers = proplists:get_value(headers, Opts, []),
+ Trailers = proplists:get_value(trailers, Opts, []),
sendfile(File, Sock, Offset, Bytes, ChunkSize, Headers, Trailers,
lists:member(sf_nodiskio,Opts),lists:member(sf_mnowait,Opts),
lists:member(sf_sync,Opts)).
@@ -432,11 +432,13 @@ sendfile(_,_,_,_,_,_,_,_,_,_) ->
%%%
sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize,
Headers, Trailers)
- when is_list(Headers) == false ->
+ when Headers == []; is_integer(Headers) ->
case sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) of
- {ok, BytesSent} when is_list(Trailers),is_integer(Headers) ->
+ {ok, BytesSent} when is_list(Trailers),
+ Trailers =/= [],
+ is_integer(Headers) ->
sendfile_send(Sock, Trailers, BytesSent+Headers);
- {ok, BytesSent} when is_list(Trailers) ->
+ {ok, BytesSent} when is_list(Trailers), Trailers =/= [] ->
sendfile_send(Sock, Trailers, BytesSent);
{ok, BytesSent} when is_integer(Headers) ->
{ok, BytesSent + Headers};
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl
index 876d266c4b..d66caad2d8 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_api_SUITE.erl
@@ -370,7 +370,7 @@ t_sendfile_hdtl(Config) ->
end,
SendHdTl = fun(Sock) ->
- Headers = [<<"header1">>,"header2"],
+ Headers = [<<"header1">>,<<0:(1024*8)>>,"header2"],
Trailers = [<<"trailer1">>,"trailer2"],
D = Send(Sock,Headers,Trailers,
iolist_size([Headers,Trailers])),