Not sure what you mean. Nothing about preadv lets you indicate you only want to read what's already in the page cache. And io_uring and preadv aren't orthogonal - you can give io_uring a preadv op to do the scattered read instead of issuing separate read OPs although I'm not 100% sure how much of a win that is in practice.
Also, I think you misunderstood the blog as it's describing application read-ahead which is what you have to do when using O_DIRECT.
> Nothing about preadv lets you indicate you only want to read what's already in the page cache.
preadv2 + RWF_NOWAIT
So I have a buffer pool with O_DIRECT reads.
I implement read-ahead in the application by (optionally) preadv:ing a single read into multiple destination buffers in the pool, leaving them unpinned, since as long as you aren't up against the bandwidth limit of the drive, a larger read is generally as fast as multiple smaller one on modern hardware.
I've tried doing this with io_uring as well, but found just eating the preadv syscall cost was faster.