Re: Git 2.54.0-rc1, subtests of t5310, t5326, t5327
- From
- Phillip Wood <phillip.wood123@gmail.com>
- Date
- Apr 9, 2026, 09:48 UTC
- Message-ID
- <90c6112d-6447-45e0-8d15-a0a3f1f25013@gmail.com>
- In-Reply-To
- <addgkjiB80pgKw69@pks.im>
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.
Thanks
Phillip
Show 111 quoted lines
> I think it should
> be the latter, but I cannot easily verify and couldn't find any docs
> around this. So could you please try the patch at the end of this mail
> to verify that it works on your system?
>
> In any case, I've tested that my patch also works when defining
> MAX_IO_SIZE to 128 bytes on my system, which hopefully demonstrates that
> it works as expected:
>
> diff --git a/git-compat-util.h b/git-compat-util.h
> index 4b4ea2498f..8e02b5f673 100644
> --- a/git-compat-util.h
> +++ b/git-compat-util.h
> @@ -690,14 +690,8 @@ static inline uint64_t u64_add(uint64_t a, uint64_t b)
> * to override this, if the definition of SSIZE_MAX given by the platform
> * is broken.
> */
> -#ifndef MAX_IO_SIZE
> -# define MAX_IO_SIZE_DEFAULT (8*1024*1024)
> -# if defined(SSIZE_MAX) && (SSIZE_MAX < MAX_IO_SIZE_DEFAULT)
> -# define MAX_IO_SIZE SSIZE_MAX
> -# else
> -# define MAX_IO_SIZE MAX_IO_SIZE_DEFAULT
> -# endif
> -#endif
> +#undef MAX_IO_SIZE
> +#define MAX_IO_SIZE 128
>
> #ifdef HAVE_ALLOCA_H
> # include <alloca.h>
>
> I'm happy to go either way, but think that we should definitely aim for
> the below patch eventually. Just let me know which way you prefer and
> I'm happy to polish up the patch.
>
> Patrick
>
> diff --git a/wrapper.c b/wrapper.c
> index be8fa575e6..645dbc5f20 100644
> --- a/wrapper.c
> +++ b/wrapper.c
> @@ -323,21 +323,50 @@ 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;
> + int i;
> +
> + /*
> + * We need to make sure that no individual iovec entry exceeds
> + * `MAX_IO_SIZE`. If there's any entry that does exceed this limit
> + * we'll pass all entries up to it to `writev()`, and then process the
> + * exceeding entry via a call to `xwrite()`.
> + */
> + for (i = 0; i < iovcnt; i++)
> + if (iov[i].iov_len > MAX_IO_SIZE)
> + break;
> + if (i < iovcnt) {
> + /*
> + * The first entry exceeds MAX_IO_SIZE, so we pass it to
> + * xwrite, which knows to handle his 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);
>