diff options
-rw-r--r-- | erts/emulator/drivers/common/efile_drv.c | 68 | ||||
-rw-r--r-- | erts/emulator/drivers/common/erl_efile.h | 15 | ||||
-rw-r--r-- | erts/emulator/drivers/unix/unix_efile.c | 2 | ||||
-rw-r--r-- | erts/preloaded/src/prim_file.erl | 35 | ||||
-rw-r--r-- | lib/kernel/src/gen_tcp.erl | 14 | ||||
-rw-r--r-- | lib/kernel/test/gen_tcp_api_SUITE.erl | 2 |
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])), |