Il giorno mer 17 dic 2025 alle ore 09:07 Paul Eggert
<[email protected]> ha scritto:
>
> On 2025-12-14 18:18, Matteo Croce wrote:
> > Il giorno dom 14 dic 2025 alle ore 01:44 Paul Eggert
> > <[email protected]> ha scritto:
> >> On 2025-12-13 08:09, Matteo Croce wrote:
> >>> That was the purpose of the patch, even if maybe I should calculate it
> >>> by using sysconf(_SC_PAGESIZE).
> >> OK, but I'm not seeing why the patch would be a good idea for the
> >> coreutils master branch. Without the patch, doesn't 'cat' work well on
> >> all porting targets? Why add an unnecessary syscall?
> > Which syscall? sysconf doesn't ask the kernel for page size.
>
> Fair enough. But why add an unnecessary call? How would it improve cat's
> behavior, from the user's viewpoint?

I'm investigating a kernel bug[1] where it seems that if (file offset
+ read size > LONG_MAX), then all I/O fails with EINVAL.

This can be triggered with a huge file:

$ truncate -s $((2**63 - 1)) file1

$ ( dd bs=1M skip=$((2**43 - 2)) count=0 && cat ) < file1
0+0 records in
0+0 records out
0 bytes copied, 2,825e-05 s, 0,0 kB/s
cat: -: Invalid argument

$ dd if=file1 bs=1M skip=$((2**43 - 2))
dd: error reading 'file1': Invalid argument
1+0 records in
1+0 records out
1048576 bytes (1,0 MB, 1,0 MiB) copied, 0,103536 s, 10,1 MB/s

or with a small file and a huge read, e.g. as in the attached file.

[1] 
https://lore.kernel.org/linux-fsdevel/[email protected]/T/

-- 
Matteo Croce

perl -e 'for($t=0;;$t++){print chr($t*($t>>8|$t>>13)&255)}' |aplay
#define _GNU_SOURCE

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
#include <err.h>

int main(int argc, char *argv[])
{
	// Just a MB less than LONG_MAX
	size_t size = LONG_MAX - (1024 * 1024);
	int in, pipefd[2], r;

	in = open(argv[1], O_RDONLY);
	if (in < 0)
		err(1, "open");

	r = pipe(pipefd);
	if (r < 0)
		err(1, "pipe");

	r = fork();
	if (r < 0)
		err(1, "fork");

	if (!r) {
		// Discard data from pipe
		char *buffer = malloc(1024 * 1024);

		while (read(pipefd[0], buffer, 1024 * 1024) > 0)
			/* do nothing */ ;

		return 0;
	}

	// splice data from file to pipe
	for (ssize_t copied = 1; copied; ) {
		copied = splice(in, NULL, pipefd[1], NULL, size, 0);
		if (copied < 0) {
			perror("splice");
			// splice() will fail when file pos + size exceeds LONG_MAX
			fprintf(stderr, "Failed to splice %zu bytes at offset %ld\n", size, lseek(in, 0, SEEK_CUR));
			return 1;
		}
	}

	return 0;
}

Reply via email to