All of lore.kernel.org
 help / color / mirror / Atom feed
From: Junio C Hamano <gitster@pobox.com>
To: Patrick Steinhardt <ps@pks.im>
Cc: git@vger.kernel.org,  Matt Smiley <msmiley@gitlab.com>,
	 "brian m. carlson" <sandals@crustytoothpaste.net>,
	 Jeff King <peff@peff.net>
Subject: Re: [PATCH v2 05/10] compat/posix: introduce writev(3p) wrapper
Date: Wed, 04 Mar 2026 14:01:18 -0800	[thread overview]
Message-ID: <xmqqseaf5k5t.fsf@gitster.g> (raw)
In-Reply-To: <20260303-pks-upload-pack-write-contention-v2-5-7321830f08fe@pks.im> (Patrick Steinhardt's message of "Tue, 03 Mar 2026 16:00:20 +0100")

Patrick Steinhardt <ps@pks.im> writes:

> In a subsequent commit we're going to add the first caller to
> writev(3p). Introduce a compatibility wrapper for this syscall that we
> can use on systems that don't have this syscall.
>
> The syscall exists on modern Unixes like Linux and macOS, and seemingly
> even for NonStop according to [1]. It doesn't seem to exist on Windows
> though.



>
> [1]: http://nonstoptools.com/manuals/OSS-SystemCalls.pdf
> [2]: https://www.gnu.org/software/gnulib/manual/html_node/writev.html
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  Makefile         |  4 ++++
>  compat/posix.h   | 14 ++++++++++++++
>  compat/writev.c  | 29 +++++++++++++++++++++++++++++
>  config.mak.uname |  2 ++
>  meson.build      |  1 +
>  5 files changed, 50 insertions(+)
>
> diff --git a/Makefile b/Makefile
> index 7f37ad8f58..cb95ff2daf 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -2021,6 +2021,10 @@ ifdef NO_PREAD
>  	COMPAT_CFLAGS += -DNO_PREAD
>  	COMPAT_OBJS += compat/pread.o
>  endif
> +ifdef NO_WRITEV
> +	COMPAT_CFLAGS += -DNO_WRITEV
> +	COMPAT_OBJS += compat/writev.o
> +endif
>  ifdef NO_FAST_WORKING_DIRECTORY
>  	BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
>  endif
> diff --git a/compat/posix.h b/compat/posix.h
> index 245386fa4a..3c611d2736 100644
> --- a/compat/posix.h
> +++ b/compat/posix.h
> @@ -137,6 +137,9 @@
>  #include <sys/socket.h>
>  #include <sys/ioctl.h>
>  #include <sys/statvfs.h>
> +#ifndef NO_WRITEV
> +#include <sys/uio.h>
> +#endif
>  #include <termios.h>
>  #ifndef NO_SYS_SELECT_H
>  #include <sys/select.h>
> @@ -323,6 +326,17 @@ int git_lstat(const char *, struct stat *);
>  ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
>  #endif
>  
> +#ifdef NO_WRITEV
> +#define writev git_writev
> +#define iovec git_iovec
> +struct git_iovec {
> +	void *iov_base;
> +	size_t iov_len;
> +};
> +
> +ssize_t git_writev(int fd, const struct iovec *iov, int iovcnt);
> +#endif
> +
>  #ifdef NO_SETENV
>  #define setenv gitsetenv
>  int gitsetenv(const char *, const char *, int);
> diff --git a/compat/writev.c b/compat/writev.c
> new file mode 100644
> index 0000000000..b77e534d5d
> --- /dev/null
> +++ b/compat/writev.c
> @@ -0,0 +1,29 @@
> +#include "../git-compat-util.h"
> +#include "../wrapper.h"
> +
> +ssize_t git_writev(int fd, const struct iovec *iov, int iovcnt)
> +{
> +	size_t total_written = 0;
> +
> +	for (int i = 0; i < iovcnt; i++) {
> +		const char *bytes = iov[i].iov_base;
> +		size_t iovec_written = 0;
> +
> +		while (iovec_written < iov[i].iov_len) {
> +			ssize_t bytes_written = xwrite(fd, bytes + iovec_written,
> +						       iov[i].iov_len - iovec_written);
> +			if (bytes_written < 0) {
> +				if (total_written)
> +					goto out;
> +				return bytes_written;
> +			}
> +			if (!bytes_written)
> +				goto out;
> +			iovec_written += bytes_written;
> +			total_written += bytes_written;
> +		}
> +	}
> +
> +out:
> +	return cast_size_t_to_ssize_t(total_written);
> +}

Because we do not check the accumulation of bytes_written in the two
accumulator variables inside the inner loop, it is very possible for
total_written to wraparound size_t and end up below the largest
value possible to be stored in ssize_t type.

IOW, the cast_size_t_to_ssize_t() introduced in the previous step is
pointless, isn't it?

According to [*1*], the real

    ssize_t writev(int fd, const struct iovec *iov, int iovcnt)

is supposed to report error with errno set to EINVAL when the sum of
iov_len member of the iov[] array elements exceed half of the
maximum size_t.

       EINVAL The sum of the iov_len values overflows an ssize_t value.

So instead of dying with cast_size_t_to_ssize_t(), we probably would
want the check done in a more stupid and straight-forward way?
Adding up iov[i].iov_len while the addition would not wraparound in
each and every step, and return error with EINVAL before attempting
even a single call to xwrite(), and then have the above double loop
that does not care about integer wraparound at all, and return
total_written with simple cast to (ssize_t)?


[Reference]

 *1* https://pubs.opengroup.org/onlinepubs/9799919799/functions/writev.html


> diff --git a/config.mak.uname b/config.mak.uname
> index 5feb582558..ccb3f71881 100644
> --- a/config.mak.uname
> +++ b/config.mak.uname
> @@ -459,6 +459,7 @@ ifeq ($(uname_S),Windows)
>  	SANE_TOOL_PATH ?= $(msvc_bin_dir_msys)
>  	HAVE_ALLOCA_H = YesPlease
>  	NO_PREAD = YesPlease
> +	NO_WRITEV = YesPlease
>  	NEEDS_CRYPTO_WITH_SSL = YesPlease
>  	NO_LIBGEN_H = YesPlease
>  	NO_POLL = YesPlease
> @@ -674,6 +675,7 @@ ifeq ($(uname_S),MINGW)
>  	pathsep = ;
>  	HAVE_ALLOCA_H = YesPlease
>  	NO_PREAD = YesPlease
> +	NO_WRITEV = YesPlease
>  	NEEDS_CRYPTO_WITH_SSL = YesPlease
>  	NO_LIBGEN_H = YesPlease
>  	NO_POLL = YesPlease
> diff --git a/meson.build b/meson.build
> index 762e2d0fc0..63514b6b84 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -1409,6 +1409,7 @@ checkfuncs = {
>    'initgroups' : [],
>    'strtoumax' : ['strtoumax.c', 'strtoimax.c'],
>    'pread' : ['pread.c'],
> +  'writev' : ['writev.c'],
>  }
>  
>  if host_machine.system() == 'windows'

  reply	other threads:[~2026-03-04 22:01 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-27 11:22 [PATCH 0/2] upload-pack: reduce lock contention when writing packfile data Patrick Steinhardt
2026-02-27 11:23 ` [PATCH 1/2] upload-pack: fix debug statement when flushing " Patrick Steinhardt
2026-02-27 11:23 ` [PATCH 2/2] upload-pack: reduce lock contention when writing " Patrick Steinhardt
2026-02-27 13:04   ` brian m. carlson
2026-02-27 18:14     ` Patrick Steinhardt
2026-02-27 17:29   ` Junio C Hamano
2026-02-27 19:37   ` Jeff King
2026-03-02 12:12     ` Patrick Steinhardt
2026-03-02 18:20       ` Jeff King
2026-03-03  9:31         ` Patrick Steinhardt
2026-03-03 13:35           ` Jeff King
2026-03-03 13:47             ` Patrick Steinhardt
2026-03-03 15:00 ` [PATCH v2 00/10] " Patrick Steinhardt
2026-03-03 15:00   ` [PATCH v2 01/10] upload-pack: fix debug statement when flushing " Patrick Steinhardt
2026-03-03 15:00   ` [PATCH v2 02/10] upload-pack: adapt keepalives based on buffering Patrick Steinhardt
2026-03-05  0:56     ` Jeff King
2026-03-10 12:08       ` Patrick Steinhardt
2026-03-03 15:00   ` [PATCH v2 03/10] upload-pack: reduce lock contention when writing packfile data Patrick Steinhardt
2026-03-05  1:16     ` Jeff King
2026-03-10 12:14       ` Patrick Steinhardt
2026-03-03 15:00   ` [PATCH v2 04/10] git-compat-util: introduce `cast_size_t_to_ssize_t()` Patrick Steinhardt
2026-03-03 15:00   ` [PATCH v2 05/10] compat/posix: introduce writev(3p) wrapper Patrick Steinhardt
2026-03-04 22:01     ` Junio C Hamano [this message]
2026-03-05  0:37       ` Jeff King
2026-03-05  2:16         ` brian m. carlson
2026-03-05  6:39           ` Johannes Sixt
2026-03-05 22:22             ` brian m. carlson
2026-03-10 12:09               ` Patrick Steinhardt
2026-03-03 15:00   ` [PATCH v2 06/10] wrapper: introduce writev(3p) wrappers Patrick Steinhardt
2026-03-03 15:00   ` [PATCH v2 07/10] sideband: use writev(3p) to send pktlines Patrick Steinhardt
2026-03-04 22:05     ` Junio C Hamano
2026-03-03 15:00   ` [PATCH v2 08/10] csum-file: introduce `hashfd_ext()` Patrick Steinhardt
2026-03-04 22:11     ` Junio C Hamano
2026-03-10 12:09       ` Patrick Steinhardt
2026-03-03 15:00   ` [PATCH v2 09/10] csum-file: drop `hashfd_throughput()` Patrick Steinhardt
2026-03-03 15:00   ` [PATCH v2 10/10] builtin/pack-objects: reduce lock contention when writing packfile data Patrick Steinhardt
2026-03-10 13:24 ` [PATCH v3 00/10] upload-pack: " Patrick Steinhardt
2026-03-10 13:24   ` [PATCH v3 01/10] upload-pack: fix debug statement when flushing " Patrick Steinhardt
2026-03-10 13:24   ` [PATCH v3 02/10] upload-pack: adapt keepalives based on buffering Patrick Steinhardt
2026-03-10 13:24   ` [PATCH v3 03/10] upload-pack: prefer flushing data over sending keepalive Patrick Steinhardt
2026-03-10 17:09     ` Junio C Hamano
2026-03-10 17:43       ` Patrick Steinhardt
2026-03-10 13:25   ` [PATCH v3 04/10] upload-pack: reduce lock contention when writing packfile data Patrick Steinhardt
2026-03-10 13:25   ` [PATCH v3 05/10] compat/posix: introduce writev(3p) wrapper Patrick Steinhardt
2026-03-10 16:59     ` Junio C Hamano
2026-03-10 13:25   ` [PATCH v3 06/10] wrapper: introduce writev(3p) wrappers Patrick Steinhardt
2026-03-10 13:25   ` [PATCH v3 07/10] sideband: use writev(3p) to send pktlines Patrick Steinhardt
2026-03-10 13:25   ` [PATCH v3 08/10] csum-file: introduce `hashfd_ext()` Patrick Steinhardt
2026-03-10 13:25   ` [PATCH v3 09/10] csum-file: drop `hashfd_throughput()` Patrick Steinhardt
2026-03-10 13:25   ` [PATCH v3 10/10] builtin/pack-objects: reduce lock contention when writing packfile data Patrick Steinhardt
2026-03-10 17:11   ` [PATCH v3 00/10] upload-pack: " Junio C Hamano
2026-03-10 20:56   ` Johannes Sixt
2026-03-11  6:27     ` Patrick Steinhardt
2026-03-13  6:45 ` [PATCH v4 " Patrick Steinhardt
2026-03-13  6:45   ` [PATCH v4 01/10] upload-pack: fix debug statement when flushing " Patrick Steinhardt
2026-03-13  6:45   ` [PATCH v4 02/10] upload-pack: adapt keepalives based on buffering Patrick Steinhardt
2026-03-13  6:45   ` [PATCH v4 03/10] upload-pack: prefer flushing data over sending keepalive Patrick Steinhardt
2026-03-13  6:45   ` [PATCH v4 04/10] upload-pack: reduce lock contention when writing packfile data Patrick Steinhardt
2026-03-13  6:45   ` [PATCH v4 05/10] compat/posix: introduce writev(3p) wrapper Patrick Steinhardt
2026-03-13  6:45   ` [PATCH v4 06/10] wrapper: introduce writev(3p) wrappers Patrick Steinhardt
2026-03-13  6:45   ` [PATCH v4 07/10] sideband: use writev(3p) to send pktlines Patrick Steinhardt
2026-03-13  6:45   ` [PATCH v4 08/10] csum-file: introduce `hashfd_ext()` Patrick Steinhardt
2026-03-13  6:45   ` [PATCH v4 09/10] csum-file: drop `hashfd_throughput()` Patrick Steinhardt
2026-03-13  6:45   ` [PATCH v4 10/10] builtin/pack-objects: reduce lock contention when writing packfile data Patrick Steinhardt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=xmqqseaf5k5t.fsf@gitster.g \
    --to=gitster@pobox.com \
    --cc=git@vger.kernel.org \
    --cc=msmiley@gitlab.com \
    --cc=peff@peff.net \
    --cc=ps@pks.im \
    --cc=sandals@crustytoothpaste.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.