Re: [PATCH] rust_binder: add TF_DEFER_COMPLETE flag for avoiding userspace roundtrip
Greg Kroah-Hartman <[email protected]>
| Newsgroups | org.kernel.vger.rust-for-linux,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <2026071743-kitten-fountain-ef10@gregkh> |
On Thu, Jul 16, 2026 at 11:20:56AM +0000, Alice Ryhl wrote: > Outgoing transactions are able to send a message and wait for its reply > in a single ioctl. Why not avoid a userspace roundtrip by applying the > same logic for replying to incoming messages and waiting for the next > incoming message? > > Generally, when you send a reply using BC_REPLY, the kernel sends > BR_TRANSACTION_COMPLETE as a reply to BC_REPLY right away. The > BR_TRANSACTION_COMPLETE command indicates that it's safe for userspace > to free any resources associated with this message (such as embedded fds > or Binder nodes). However, the BR_TRANSACTION_COMPLETE message is > problematic because after BC_REPLY is issued, there will be a pending > message for userspace. The kernel will refuse to sleep for incoming > messages in this scenario. > > The way this is handled for outgoing transaction is through a mechanism > known as deferred delivery of BR_TRANSACTION_COMPLETE. The idea is that > when you send an outgoing transaction, then we do not return to > userspace right away if BR_TRANSACTION_COMPLETE is the only pending > message. This patch adds a new flag called TF_DEFER_COMPLETE that lets > userspace opt-in to the same deferred delivery mechanism for > BR_TRANSACTION_COMPLETE when using BC_REPLY. > > Given this new uapi, we can adjust sendReply in userspace libbinder > so that it writes the BC_REPLY command into mOut but does not flush the > buffer to the kernel. Then, userspace simply continues running until it > returns all the way out to the top-level joinThreadPool() loop, which > calls into the kernel to get the next incoming transaction. At this > point, mOut is flushed, sending the reply. The same ioctl then proceeds > to sleep for an incoming message. > > Userspace only actually specifies TF_DEFER_COMPLETE when the Parcel does > not contain fds or refcounts on binder objects. This is because > otherwise said fd or binder node will not be freed until the binder > thread receives another incoming transaction, which could be a long > time. In the case of fds, this is especially important because delaying > fclose() can result in processes hanging because they read from a pipe > that isn't being closed due to fclose() not getting called. Note that > even if TF_DEFER_COMPLETE is not specified for this transaction, it can > still be useful to defer the BC_REPLY command, as it can still avoid a > userspace roundtrip when a new incoming transaction is available right > away. > > Observing the cuttlefish logs while booting with this change shows that > there were 4297 opportunities for this optimization to kick in (that is, > boot invoked BC_REPLY 4297 times). Out of those, 3441 binder ioctls sent > and received a transaction in the same ioctl. This indicates that we > successfully eliminated a syscall on the server side for 80% of incoming > transactions. Generally, this means that a server is now able to handle > incoming messages using one syscall per incoming message (for each > incoming transaction, the syscall handles one BC_FREE_BUFFER and > BC_REPLY command, and then waits for the next incoming transaction). > > Signed-off-by: Alice Ryhl <[email protected]> Does not apply against the char-misc-testing branch :(