diff options
author | Björn Gustavsson <[email protected]> | 2016-03-29 09:10:13 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2016-04-04 14:37:15 +0200 |
commit | 5ae46e823a8a52ed4e5b960ff62975894b1a8302 (patch) | |
tree | b782b23d89d388ad4daa922ebc4ddea269802e35 /erts/emulator/drivers/unix/unix_efile.c | |
parent | 1244cebc4b369cfd53ae775ea7380c61ed98ed64 (diff) | |
download | otp-5ae46e823a8a52ed4e5b960ff62975894b1a8302.tar.gz otp-5ae46e823a8a52ed4e5b960ff62975894b1a8302.tar.bz2 otp-5ae46e823a8a52ed4e5b960ff62975894b1a8302.zip |
Handle multi-giga byte writes to files
Test cases that write 4Gb to a file at once would fail on
OS X and FreeBSD.
By running a simple test program on OS X (El Capitan 10.11.4/Darwin
15.4.0), I found that writev() can handle more than 4Gb of data, while
write() only can handle less than 2Gb. (Note that efile_drv.c will use
write() if there is only one element in the io vector, and writev() if
there is more than one.)
It is tempting to attempt to piggy-back on the existing mechanism
for segmenting write operations in efile_drv.c, but because of the
complex code I find it too dangerous, both from a correctness and
performance perspective.
Instead do the change in unix_efile.c, which is considerably
simpler.
Diffstat (limited to 'erts/emulator/drivers/unix/unix_efile.c')
-rw-r--r-- | erts/emulator/drivers/unix/unix_efile.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index ac9b681d03..c097bc1950 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -638,12 +638,21 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ do { w = writev(fd, &iov[cnt], b); } while (w < 0 && errno == EINTR); + if (w < 0 && errno == EINVAL) { + goto single_write; + } } else + single_write: /* Degenerated io vector - use regular write */ #endif { do { - w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len); + size_t iov_len = iov[cnt].iov_len; + size_t limit = 1024*1024*1024; /* 1GB */ + if (iov_len > limit) { + iov_len = limit; + } + w = write(fd, iov[cnt].iov_base, iov_len); } while (w < 0 && errno == EINTR); ASSERT(w <= iov[cnt].iov_len || (w == -1 && errno != EINTR)); |