Re: Git 2.54.0-rc1, subtests of t5310, t5326, t5327
- From
Patrick Steinhardt <ps@pks.im>
- Date
- Apr 9, 2026, 11:29 UTC
- Message-ID
- <adeNjEBSlXd7ykEx@pks.im>
- In-Reply-To
- <90c6112d-6447-45e0-8d15-a0a3f1f25013@gmail.com>
On Thu, Apr 09, 2026 at 10:48:02AM +0100, Phillip Wood wrote:
Show 13 quoted lines
> On 09/04/2026 09:17, Patrick Steinhardt wrote: > > > > One question to Randall though: does MAX_IO_SIZE apply to the overall > > size of the iovec or to the individual iovec entries? > > In <014e01dcc793$8a9bab90$9fd302b0$@nexbridge.com> Randall says > > Specifying the sum of the iov_len values in the iov array greater > than the OSS I/O size limit for that open causes the writev() > function to return -1 and set errno to [EINVAL]. > > So it is the overall size which fits with POSIX limiting to overall size to > SSIZE_MAX.
Ah, thanks for the pointer. I've adapted the patch a bit to the below one. Again, I've tested it with `#define MAX_IO_SIZE 100` to verify that it works as expected.
I guess I'll send a polished version to the mailing list in a bit.
Patrick
diff --git a/wrapper.c b/wrapper.c index be8fa575e6..d989c78b4b 100644 --- a/wrapper.c +++ b/wrapper.c @@ -323,21 +323,60 @@ ssize_t write_in_full(int fd, const void *buf, size_t count) return total; } +ssize_t xwritev(int fd, struct iovec *iov, int iovcnt) +{ + ssize_t bytes_written; + size_t total_length; + int i; + + /* + * We need to make sure that writev(3p) call does not write more than + * `MAX_IO_SIZE` many bytes. If we do exceed that limit, we only pass + * those iovecs to writev(3p) that sum up to less than the limit. + * + * If on the other hand the first iovec entry already exceeds this + * limit we'll instead use xwrite() to write it, which knows to handle + * `MAX_IO_SIZE` for us. + */ + for (i = 0, total_length = 0; i < iovcnt; i++) { + if (unsigned_add_overflows(total_length, iov[i].iov_len)) + break; + + total_length += iov[i].iov_len; + if (total_length > MAX_IO_SIZE) + break; + } + + if (i < iovcnt) { + /* + * The first entry exceeds MAX_IO_SIZE, so we pass it to + * xwrite, which knows to handle this case. + */ + if (!i) + return xwrite(fd, iov->iov_base, iov->iov_len); + iovcnt = i; + } + + bytes_written = writev(fd, iov, iovcnt); + if (!bytes_written) { + errno = ENOSPC; + return -1; + } + + return bytes_written; +} + ssize_t writev_in_full(int fd, struct iovec *iov, int iovcnt) { ssize_t total_written = 0; while (iovcnt) { - ssize_t bytes_written = writev(fd, iov, iovcnt); - if (bytes_written < 0) { + ssize_t bytes_written = xwritev(fd, iov, iovcnt); + if (bytes_written <= 0) { if (errno == EINTR || errno == EAGAIN) continue; return -1; } - if (!bytes_written) { - errno = ENOSPC; - return -1; - } total_written += bytes_written; diff --git a/wrapper.h b/wrapper.h index 27519b32d1..a6287d7f4d 100644 --- a/wrapper.h +++ b/wrapper.h @@ -16,6 +16,7 @@ void *xmmap_gently(void *start, size_t length, int prot, int flags, int fd, off_ int xopen(const char *path, int flags, ...); ssize_t xread(int fd, void *buf, size_t len); ssize_t xwrite(int fd, const void *buf, size_t len); +ssize_t xwritev(int fd, struct iovec *iov, int iovcnt); ssize_t xpread(int fd, void *buf, size_t len, off_t offset); int xdup(int fd); FILE *xfopen(const char *path, const char *mode);