Page MenuHomeFreeBSD

Fully handle size_t values in AIO requests.
ClosedPublic

Authored by jhb on Mar 18 2016, 9:52 PM.
Tags
None
Referenced Files
Unknown Object (File)
Tue, Apr 30, 12:56 PM
Unknown Object (File)
Sat, Apr 27, 4:53 PM
Unknown Object (File)
Mar 18 2024, 1:31 PM
Unknown Object (File)
Mar 5 2024, 5:42 PM
Unknown Object (File)
Mar 2 2024, 10:19 AM
Unknown Object (File)
Jan 14 2024, 6:09 PM
Unknown Object (File)
Jan 11 2024, 6:24 PM
Unknown Object (File)
Dec 20 2023, 12:23 AM
Subscribers

Details

Reviewers
kib
allanjude
Group Reviewers
manpages
Summary

Fully handle size_t values in AIO requests.

First, update the return types of aio_return() and aio_waitcomplete() to
ssize_t.

POSIX requires aio_return() to return a ssize_t so that it can represent
all return values from read() and write(). aio_waitcomplete() should use
ssize_t for the same reason.

aio_return() has used ssize_t in <aio.h> since r31620 but the manpage and
system call entry were not updated. aio_waitcomplete() has always
returned int.

Note that this does not require new system call stubs as this is
effectively only an API change in how the compiler interprets the return
value. The system calls have always returned a full register.

Second, allow aio_nbytes values up to SSIZE_MAX instead of just INT_MAX.

Additional thoughts:

In theory the second change should require compat versions of all the system
calls that accept an aiocb since aio_waitcomplete() can now return a
value > INT_MAX. This check made the aio_waitcomplete() return type
change a no-op, but with it updated it is in theory no longer one.

Given that aio_return() has been correct since 1997 and that
aio_waitcomplete() is FreeBSD-specific and not in POSIX, I'd probably
vote to just permit this particular ABI breakage vs the cost of adding
wrappers for several aio system calls. Hopefully any old binaries that
are using aio_waitcomplete() aren't relying on aio_read/write to fail
if aio_nbytes is above INT_MAX. (The old binaries I can think of are
i386 for which this doesn't matter.)

Test Plan
  • Run 32 and 64-bit versions of the aio tests in src/tests/sys/aio on amd64.
  • make tinderbox

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 2970
Build 2998: arc lint + arc unit

Event Timeline

jhb retitled this revision from to Fully handle size_t values in AIO requests..
jhb updated this object.
jhb edited the test plan for this revision. (Show Details)
jhb added a reviewer: kib.
sys/kern/vfs_aio.c
1449

We don't have a similar check in read(2) or write(2) which I find puzzling. There are several places where we store counts as longs or ints instead of size_t though. The 'status' member in aiocb_private (we could fix that to be size_t), the 'cnt' variable in aio_process_rw() (that just needs to be converted from an int to a size_t, though it is compared with uio_resid which is a ssize_t, perhaps 'cnt' should be a ssize_t instead?)

2621

I'm not sure if I need these? In theory using values > 2^31 here when size_t is 64 bits means that casting the "real" value (stored in a size_t below) won't sign extend and thus will never be negative. OTOH, that means that a binary running under compat32 can try to use larger I/O requests than a native binary.

jhb edited edge metadata.
  • More size_t fixes.

Fixing the return types isn't enough, the system call implementations
were using 'int' instead of 'long' so they were truncating both the
value written to the job in userland and the return values. Also,
the 'cnt' variable in aio_process_rw() was an int.

sys/kern/vfs_aio.c
1449

I am not sure I follow the note about read/write. Do you mean that IOSIZE_MAX checks are wrong or not effective ?

2621

The 32bit kernel would return EINVAL in this situation, am I right ?

sys/kern/vfs_aio.c
1449

No, I just misread the code. Thanks. Clearly I should be using IOSIZE_MAX here so that aio_read/write honor the tunable to cap IO sizes at INT_MAX.

2621

Yes. In the 32-bit kernel these requests would hit the IOSIZE_MAX check. Note, however, that we don't have a freebsd32_read() that enforces INT_MAX always for IOSIZE_MAX (which is what this change is effectively doing for aio_read()). 32-bit binaries call the native read() / write() directly. Alternatively, we could "fix" IOSIZE_MAX to always be INT_MAX if SV_ILP32 is set? That would be an orthogonal change that would fix read() and write() as well as the AIO calls (and I wouldn't need this explicit check here).

jhb edited edge metadata.
  • Use IOSIZE_MAX instead of SSIZE_MAX.
kib edited edge metadata.
kib added inline comments.
sys/kern/vfs_aio.c
2621

SV_ILP32 conditional sounds as a good idea.

This revision is now accepted and ready to land.Mar 19 2016, 7:20 PM
jhb edited edge metadata.
  • Drop the explicit INT_MAX checks in freebsd32 compat.
This revision now requires review to proceed.Mar 19 2016, 7:58 PM
kib edited edge metadata.
This revision is now accepted and ready to land.Mar 19 2016, 8:18 PM
jhb edited edge metadata.
  • Add a test for "large" I/O operations.
  • Compile.
  • Compile some more.
  • Trim newlines.
  • Use a temporary file instead of /dev/null.
This revision now requires review to proceed.Mar 21 2016, 9:27 PM
This revision is now accepted and ready to land.Mar 21 2016, 10:06 PM