Skip to content

[GIT PULL] man/io_uring_prep_read.3: Explain unsigned input vs. __s32 output#1570

Merged
axboe merged 1 commit intoaxboe:masterfrom
andrew-sayers:master
Apr 23, 2026
Merged

[GIT PULL] man/io_uring_prep_read.3: Explain unsigned input vs. __s32 output#1570
axboe merged 1 commit intoaxboe:masterfrom
andrew-sayers:master

Conversation

@andrew-sayers
Copy link
Copy Markdown
Contributor

io_uring_prep_read() reads an unsigned number of bytes, and for short reads it returns the actual number of bytes read. But the return value is __s32, so not all possible values can be represented.

Explain that it's impossible to allocate a buffer large enough for this to be a problem.

I'm submitting this as a PR with an answer I think is correct, but could just as easily have raised an issue asking a question. Happy to resubmit if there's an actual bug here, like an architecture with a weird PTRDIFF_MAX or a way to pass very large buffers to io_uring_prep_read(). Otherwise, this seems like the best way to avoid the next person spending an hour running this one to ground.


git request-pull output:

The following changes since commit 457d6b0fc1e0fb29eb48b77bb50c31e9d946cac4:

  test/fd-pass: skip on older kernels without DEFER_TASKRUN (2026-04-21 16:09:50 -0600)

are available in the Git repository at:

  https://github.com/andrew-sayers/liburing master

for you to fetch changes up to 893bd7c27460bee0bf601d609e6e0ccd3e10ce04:

  man/io_uring_prep_read.3: Explain unsigned input vs. __s32 output (2026-04-23 15:38:28 +0100)

----------------------------------------------------------------
Andrew Sayers (1):
      man/io_uring_prep_read.3: Explain unsigned input vs. __s32 output

 man/io_uring_prep_read.3 | 5 +++++
 1 file changed, 5 insertions(+)

By submitting this pull request, I acknowledge that:

  1. I have followed the above pull request guidelines.
  2. I have the rights to submit this work under the same license.
  3. I agree to a Developer Certificate of Origin (see https://developercertificate.org for more information).

@axboe
Copy link
Copy Markdown
Owner

axboe commented Apr 23, 2026

Missing a signed-off-by in the commit. That aside, the main thing here is that no syscalls in Linux ever accept more than INT_MAX as the transfer size. Hence it'll always fit in a signed int. Any change should mention that too. The prep helpers should've made this clear from the get-go, but...

io_uring_prep_read() reads an unsigned number of bytes,
and for short reads it returns the actual number of bytes read.
But the return value is __s32, so not all possible values
can be represented.

Explain this doesn't matter because of limits in the underlying syscall.

Signed-off-by: Andrew Sayers <andrew-github.com@pileofstuff.org>
@andrew-sayers
Copy link
Copy Markdown
Contributor Author

Ah yes, I must have skipped past the explanation in read(2) because I was busy looking for data types instead of maximum values. This version lifts the phrase "the number of bytes actually transferred" from that page, so anyone else who makes the same mistake will know the phrase to search for.

@axboe axboe merged commit 0fbff3e into axboe:master Apr 23, 2026
20 checks passed
@axboe
Copy link
Copy Markdown
Owner

axboe commented Apr 23, 2026

Merged this one, but would actually be interesting to have this blurb in other liburing man pages where a transfer size is used. If you feel so inclined...

@andrew-sayers
Copy link
Copy Markdown
Contributor Author

Ok, I kinda got sucked into the bigger job :)

Before I submit a PR, can you confirm...

  • this is the complete list of man pages where a transfer size is used:
    • man/io_uring_prep_read.3
    • man/io_uring_prep_read_fixed.3
    • man/io_uring_prep_recv.3
    • man/io_uring_prep_send.3
    • man/io_uring_prep_tee.3
    • man/io_uring_prep_write.3
    • man/io_uring_prep_write_fixed.3
  • there is no size limit for the following:
    • man/io_uring_prep_readv.3
    • man/io_uring_prep_readv_fixed.3
    • man/io_uring_prep_writev.3
    • man/io_uring_prep_writev_fixed.3

(I plan to add a note to the second set of pages saying the issue doesn't apply, and recommend them from the pages where it does apply)

Aside: read(2) implies there's a read()-specific limit of 0x7ffff000 bytes (confirmed in a quick test). It's the only page I've found that talks about such a limit, so I'll write different blurbs for read() and non-read() pages.

@axboe
Copy link
Copy Markdown
Owner

axboe commented Apr 23, 2026

Ok, I kinda got sucked into the bigger job :)

The art of maintaining open source software ;-)

List looks good to me. There's the iov.iov_len for the vectored interfaces, so I do think it makes sense to put in there too. Not that those differ from the other ones, but just for completeness. I'd also include:

  • io_uring_prep_splice(3)
  • io_uring_prep_read_multishot(3)
  • io_uring_prep_send_zc(3)
  • io_uring_prep_sync_file_range(3)

And I think that is it. Thanks again for doing this - not just the first PR, because it is always nice when someone submits a documentation change for something that caused them headache, but also for doing the rest of them.

andrew-sayers added a commit to andrew-sayers/liburing that referenced this pull request Apr 24, 2026
Tweak the discussion text from e65a2a0, and replicate it across all
read()-based functions.

Linux's read() function has special limitations, so the text in these
functions should be visibly different to the blurb elsewhere.
To achieve that, io_uring_cqe's result code is only discussed explicitly
in this commit.

Based on a discussion in axboe#1570

Signed-off-by: Andrew Sayers <andrew-github.com@pileofstuff.org>
andrew-sayers added a commit to andrew-sayers/liburing that referenced this pull request Apr 24, 2026
Based on a discussion in axboe#1570

Signed-off-by: Andrew Sayers <andrew-github.com@pileofstuff.org>
andrew-sayers added a commit to andrew-sayers/liburing that referenced this pull request Apr 24, 2026
Based on a discussion in axboe#1570

Signed-off-by: Andrew Sayers <andrew-github.com@pileofstuff.org>
andrew-sayers added a commit to andrew-sayers/liburing that referenced this pull request Apr 24, 2026
io_uring_buf_ring_add(3) does not transfer data, but people reading that
page are likely to appreciate a hint about maximum buffer sizes.

A quick test shows splice(3) and tee(3) don't return much data per call.
If a user saw text in io_uring_prep_splice(3) or io_uring_prep_tee(3)
that looked just like the other man pages, they would have the right
to be surprised when they found the functions behaved differently.
The man pages for splice and tee don't mention any particular limits,
so these man pages just say "limits as low as 65536 have been observed" -
specific enough to alert the reader, but vague enough not to imply
undue certainty.

Based on a discussion in axboe#1570

Signed-off-by: Andrew Sayers <andrew-github.com@pileofstuff.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants