-
Notifications
You must be signed in to change notification settings - Fork 130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed buffers to support ReadFixed and WriteFixed ops #54
Conversation
@mzabaluev any interest in completing this? |
@Noah-Kennedy Yes, I should update the PR at least, will get to it soon. |
I have rebased the branch. The tests (after merging with #52) sporadically fail, but I see the same flakeyness in master. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the api for Buffers::new is flawed, and should instead take a buffer and fragment it internally.
@mzabaluev Can we try again and get this merged? You put a lot of work into this. I can get up to speed on it shortly if you wanted to rebase with master. Perhaps wait for the other merge we might pick up first so the rebase only has to be done once more. |
@FrankReh I'll try to rebase the branch this week. |
This API allows pre-registering an arbitrary set of pre-allocated buffers. While it's true that each buffer needs to be allocated separately, registering is meant to be a one-time operation for the lifetime of |
BufRegistry keeps track of buffers that are pre-registered with the IoUring instance and can be checked out for use as FixedBuf handles.
This is used by a new read_fixed_at method on File.
Used by a new write_fixed_at method on File.
This supports the io_uring_register facility for buffer deregistration, allowing different buffer sets to be registered over the lifetime of an io-uring descriptor. As long as the old buffer allocations are kept alive by BufRegistry or FixedBuf instances referring to them, there is no ambiguity for the kernel when an old buffer instance is erroneously used after its registration is revoked, even if the buffer index has since been reused for a newly registered buffer, because the new buffer has to use a different memory allocation.
When BufRegistry::unregister is called, but some FixedBuf handles obtained from that BufRegistry instance are still around, operations using these handles are expected to fail gracefully even if the buffer indices have since been re-registered for new buffers. This is an edge case, but adding a test for it validates the design with the capability to unregister the previously registered buffers and register new ones while in the same io-uring runtime context.
Test that a FixedBuf is correctly checked out from a BufRegistry by index, and cannot be checked out more than once while the buffer is either referenced by the FixedBuf handle, or used by an operation in flight.
Examples on File::read_fixed_at and File::write_fixed_at get this treatment, as they are added in the same PR.
The blocking is no longer observed as of kernel 5.19.16 on x86_64.
a52cf73
to
6fb48bb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API provided by this PR needs to be evaluated in light of the pbuf_ring support that is going to this crate in the next week or so.
This is dodgy, but Slice derefs to a byte slice too.
Thanks @FrankReh and @Noah-Kennedy for getting #172 merged. The API here is much nicer now, both |
I'll try to review now. Took a quick glance and they did look cleaner. But @Noah-Kennedy will be anxious to get his moved files in so this may have to go through another rebase. From his move diffs though, mostly files were moved with no symbol name changes, but the odd use or mod change. I don't know if git will be making that easy for you to merge or rebase with or not. But before doing too much manual work, probably want to wait for Noah to also bless this type of work. I don't think he's commented on it recently. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it looks very good. As with all things so complex, there will be many color choices to paint the shed. I would love to see this go in, even if there are things to change down the road - although right now I'm not thinking of any. I can't tell you how many times I thought about doing something with indexed buffers only to then remember that they aren't in the library yet.
Going to wait for @Noah-Kennedy to decide the timing of this merge, or to provide his own review too of course. |
I just merged #180, so this needs a rebase. I'll review once that happens. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. One comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about parts of this.
I'm a bit concerned about soundness in the case where buffers are checked out and then unregistered. If my understanding is correct, a user could safely cause undefined behavior by using the deref implementation of an existing buffer after the set of buffers has been unregistered.
I'm also uncomfortable with the idea of this being able to leak buffers this easily.
I don't necessarily have solutions to these issues right now, but they need solved before we can merge.
Unregistering the buffers does not get them deallocated, as long as there is a My concern is rather that it's not necessarily easy to know the moment when the buffers get dropped. But:
The only problem I see is that leaking a single |
@Noah-Kennedy I think you raised two concerned about 12 hours ago and @mzabaluev gave some feedback 7 hours ago. Do you still believe holding a reference to a buffer after the kernel has had the buffers unregistered is a problem? I may just be repeating @mzabaluev , but I believe the memory has not been freed in that case so no UB there, and the kernel would reject further attempts at using that buffer (but it would have had to be owned, not just referenced). So maybe not a problem? On the second concern, where do you see buffers being leaked? Or is that part of the first concern and @mzabaluev and I don't follow your point, or you've changed your mind on it? |
Sorry about the responsiveness, I'm traveling at moment. @mzabaluev thanks for the clarification, I see that I misread how that is tracked. I'm in favor of merging. |
@FrankReh I'll leave the merging to you as I'm getting on a plane in just a moment. |
@Noah-Kennedy @mzabaluev I think we should have an extras module parent, maybe you have a better name. A place in the repo for some extra modules that aren't needed by the driver or the ops but that a user may want for common tasks. The fixed indexes begs for one or more implementations of sets of buffers. One where the next is supported, as @mzabaluev has called out before. I'm also wondering about one where next would be a Future so one could await the next free index. Let's say I create an index registry with 1000 buffers and I don't want to drop a service if another buffer isn't available, but rather I want to wait for one to free up. Once it is behind a Future, it could also be behind a timed Future that does something different if a buffer isn't freed in a reasonable amount of time. |
I'm fully in agreement here. |
Thanks for shepherding this!
I'm pretty sure I can work two
I think it's also feasible to implement an async
I can't think of anything that can't be achieved with existing composing APIs like |
Not to confuse anyone, I totally saw using the tokio timeout future. Didn't mean it would be built into our library or an extras module. Just that waiting for the next would be useful and then it's easy to break out with a timeout too if the situation calls for it. Guess I was stating the obvious and that was confusing. |
Add infrastructure to manage pre-registered buffers, and operation methods
File::read_fixed_at
andFile::write_fixed_at
to make use of them. Exclusive access to buffer data between the application and in-flight ops is controlled at runtime.This is initial API to enable fixed buffers. Future developments may include:
Improve the ergonomics of .slice with IntoSlice trait #53BoundedBuf
trait to take.slice
API out ofIoBuf
#172;FixedBufRegistry
without enumerating or keeping track of indices;IORING_REGISTER_BUFFERS2
/IORING_REGISTER_BUFFERS_UPDATE
.Needs #52 to get tests to pass.