Can only guess, but in operating system interfaces, stability is important.
read returns an ssize_t, which might be 64 bit (allowing for sizes up to 63 bit, because, well, the first s is for signed). But that's not always been that way.
Functionally, for the most of the first 25 years of C and POSIX history, that was just the same as int. In fact, it was int, up to relatively recently, in System V Release 4 (Programmers Reference Manual Page 307), in BSD4.3 (UNIX Programmer's Reference Manual).
So, programmers were right to assume this call can only return as many bytes as INT_MAX was. So, on your massive 64 bit machine allocate 2GB of buffer, int howmany = read(fd, buffer, (unsigned int) INT_MAX); done. Due to the API, read cannot ever read more than INT_MAX (minus one page, after all, the process that calls read needs to have at least 1 page of executable memory), which is the largest signed 32 bit integer.
Now imagine what happens if your compiler switches int to a 64 bit type (this is not the standard for GCC on x86_64 or aarch64, but it can and has happened on UNIX systems). Suddenly, you're not reading up to INT_MAX items, but INT64_MAX items into a INT_MAX buffer.
Yeah, that's a buffer overflow due to the implementation of the syscall actually "growing" with its API. It makes kittens sad.
So, instead, Linux decided that, meh, let's not do that, whoever needs to read more than 2GB can call read multiple time.
This has one very important "downside" from the user perspective: POSIX read (and readv, which I tested will not read more than read at once, bummer, on Linux) is atomic, meaning even if other threads or processes work on the same file descriptor, you can be sure that the offset will not be shifted on the middle of reading.
Maybe, that's, however, also an OS design decision: If you're doing a file operation larger than 2 GB, you better figure out an application-level mutually exclusive file access scheme than to expect the kernel to keep some handle consistent for such a large, and long-duration, operation.
read()already needs to be able to read an arbitrary amount of bytes, at an arbitrary file position, so even if 0x7fffffff = 2147483647 is a prime, it shouldn't matter.#define MAX_RW_COUNT (INT_MAX & PAGE_MASK)in the code (ininclude/linux/fs.h).git log/blamemight allow you to get back to the rationale