From: Andreas Hindborg <nmi@metaspace.dk>
To: Ming Lei <ming.lei@redhat.com>
Cc: "Miguel Ojeda" <miguel.ojeda.sandonis@gmail.com>,
"Jens Axboe" <axboe@kernel.dk>, "Keith Busch" <kbusch@kernel.org>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Christoph Hellwig" <hch@lst.de>,
"Damien Le Moal" <Damien.LeMoal@wdc.com>,
"Bart Van Assche" <bvanassche@acm.org>,
"Hannes Reinecke" <hare@suse.de>,
"linux-block@vger.kernel.org" <linux-block@vger.kernel.org>,
"Andreas Hindborg" <a.hindborg@samsung.com>,
"Wedson Almeida Filho" <wedsonaf@gmail.com>,
"Niklas Cassel" <Niklas.Cassel@wdc.com>,
"Greg KH" <gregkh@linuxfoundation.org>,
"Matthew Wilcox" <willy@infradead.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <benno.lossin@proton.me>,
"Alice Ryhl" <aliceryhl@google.com>,
"Chaitanya Kulkarni" <chaitanyak@nvidia.com>,
"Luis Chamberlain" <mcgrof@kernel.org>,
"Yexuan Yang" <1182282462@bupt.edu.cn>,
"Sergio González Collado" <sergio.collado@gmail.com>,
"Joel Granados" <j.granados@samsung.com>,
"Pankaj Raghav (Samsung)" <kernel@pankajraghav.com>,
"Daniel Gomez" <da.gomez@samsung.com>,
"open list" <linux-kernel@vger.kernel.org>,
"rust-for-linux@vger.kernel.org" <rust-for-linux@vger.kernel.org>,
"lsf-pc@lists.linux-foundation.org"
<lsf-pc@lists.linux-foundation.org>,
"gost.dev@samsung.com" <gost.dev@samsung.com>
Subject: Re: [RFC PATCH 1/5] rust: block: introduce `kernel::block::mq` module
Date: Fri, 15 Mar 2024 18:49:39 +0100 [thread overview]
Message-ID: <87il1nqtak.fsf@metaspace.dk> (raw)
In-Reply-To: <ZfRoJxzOLZEIaQK7@fedora> (Ming Lei's message of "Fri, 15 Mar 2024 23:24:23 +0800")
Ming Lei <ming.lei@redhat.com> writes:
> On Fri, Mar 15, 2024 at 01:46:30PM +0100, Andreas Hindborg wrote:
>> Ming Lei <ming.lei@redhat.com> writes:
>> > On Fri, Mar 15, 2024 at 08:52:46AM +0100, Andreas Hindborg wrote:
>> >> Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> writes:
>> >>
>> >> > On Thu, Mar 14, 2024 at 8:23 PM Andreas Hindborg <nmi@metaspace.dk> wrote:
>> >> >>
>> >> >> The way the current code compiles, <kernel::block::mq::Request as
>> >> >> kernel::types::AlwaysRefCounted>::dec_ref` is inlined into the `rnull`
>> >> >> module. A relocation for `rust_helper_blk_mq_free_request_internal`
>> >> >> appears in `rnull_mod.ko`. I didn't test it yet, but if
>> >> >> `__blk_mq_free_request` (or the helper) is not exported, I don't think
>> >> >> this would be possible?
>> >> >
>> >> > Yeah, something needs to be exported since there is a generic
>> >> > involved, but even if you want to go the route of exporting only a
>> >> > different symbol, you would still want to put it in the C header so
>> >> > that you don't get the C missing declaration warning and so that we
>> >> > don't have to write the declaration manually in the helper.
>> >>
>> >> That is what I did:
>> >>
>> >> @@ -703,6 +703,7 @@ int blk_mq_alloc_sq_tag_set(struct blk_mq_tag_set *set,
>> >> unsigned int set_flags);
>> >> void blk_mq_free_tag_set(struct blk_mq_tag_set *set);
>> >>
>> >> +void __blk_mq_free_request(struct request *rq);
>> >> void blk_mq_free_request(struct request *rq);
>> >> int blk_rq_poll(struct request *rq, struct io_comp_batch *iob,
>> >> unsigned int poll_flags);
>> >
>> > Can you explain in detail why one block layer internal helper is
>> > called into rnull driver directly? It never happens in C driver code.
>>
>> It is not the rust null block driver that calls this symbol directly. It
>> is called by the Rust block device driver API. But because of inlining,
>> the symbol is referenced from the loadable object.
>
> What is the exact Rust block device driver API? The key point is that how
> the body of one exported kernel C API(EXPORT_SYMBOL) becomes inlined
> with Rust driver.
This happens when `ARef<Request<_>>` is dropped. The drop method
(destructor) of this smart pointer decrements the refcount and
potentially calls `__blk_mq_free_request`.
>>
>> The reason we have to call this symbol directly is to ensure proper
>> lifetime of the `struct request`. For example in C, when a driver
>
> Sounds Rust API still calls into __blk_mq_free_request() directly, right?
Yes, the Rust block device driver API will call this request if an
`ARef<Request<_>>` is dropped and the refcount goes to 0.
> If that is the case, the usecase need to be justified, and you need
> to write one standalone patch with the exact story for exporting
> __blk_mq_free_request().
Ok, I can do that.
>
>> converts a tag to a request, the developer makes sure to only ask for
>> requests which are outstanding in the driver. In Rust, for the API to be
>> sound, we must ensure that the developer cannot write safe code that
>> obtains a reference to a request that is not owned by the driver.
>>
>> A similar issue exists in the null block driver when timer completions
>> are enabled. If the request is cancelled and the timer fires after the
>> request has been recycled, there is a problem because the timer holds a
>> reference to the request private data area.
>>
>> To that end, I use the `atomic_t ref` field of the C `struct request`
>> and implement the `AlwaysRefCounted` Rust trait for the request type.
>> This is a smart pointer that owns a reference to the pointee. In this
>> way, the request is not freed and recycled until the smart pointer is
>> dropped. But if the smart pointer holds the last reference when it is
>> dropped, it must be able to free the request, and hence it has to call
>> `__blk_mq_free_request`.
>
> For callbacks(queue_rq, timeout, complete) implemented by driver, block
> layer core guaranteed that the passed request reference is live.
>
> So driver needn't to worry about request lifetime, same with Rust
> driver, I think smart pointer isn't necessary for using request in
> Rust driver.
Using the C API, there is nothing preventing a driver from using the
request after the lifetime ends. With Rust, we have to make it
impossible. Without the refcount and associated call to
`__blk_mq_free_request`, it would be possible to write Rust code that
access the request after the lifetime ends. This is not sound, and it is
something we need to avoid in the Rust abstractions.
One concrete way to do write unsound code with a Rust API where lifetime
is not tracked with refcount, is if the null block timer completion
callback fires after the request is completed. Perhaps the driver
cancels the request but forgets to cancel the timer. When the timer
fires, it will access the request via the context pointer, but the
request will be invalid. In C we have to write the driver code so this
cannot happen. In Rust, the API must prevent this from happening. So any
driver written in the safe subset of Rust using this API can never
trigger this behavior.
By using the refcount, we ensure that the request is alive until all
users who hold a reference to it are dropped.
Another concrete example is when a driver calls `blk_mq_tag_to_rq` with
an invalid tag. This can return a reference to an invalid tag, if the
driver is not implemented correctly. By using `req_ref_inc_not_zero` we
can assert that the request is live before we create a Rust reference to
it, and even if the driver code has bugs, it can never access an invalid
request, and thus it can be memory safe.
We move the responsibility of correctness, in relation to memory safety,
from the driver implementation to the API implementation.
Best regards,
Andreas
next prev parent reply other threads:[~2024-03-15 17:49 UTC|newest]
Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-13 11:05 [RFC PATCH 0/5] Rust block device driver API and null block driver Andreas Hindborg
2024-03-13 11:05 ` [RFC PATCH 1/5] rust: block: introduce `kernel::block::mq` module Andreas Hindborg
2024-03-13 23:55 ` Boqun Feng
2024-03-14 8:58 ` Andreas Hindborg
2024-03-14 18:55 ` Miguel Ojeda
2024-03-14 19:22 ` Andreas Hindborg
2024-03-14 19:41 ` Andreas Hindborg
2024-03-14 19:41 ` Miguel Ojeda
2024-03-14 20:56 ` Miguel Ojeda
2024-03-15 7:52 ` Andreas Hindborg
2024-03-15 12:17 ` Ming Lei
2024-03-15 12:46 ` Andreas Hindborg
2024-03-15 15:24 ` Ming Lei
2024-03-15 17:49 ` Andreas Hindborg [this message]
2024-03-16 14:48 ` Ming Lei
2024-03-16 17:27 ` Andreas Hindborg
2024-03-13 11:05 ` [RFC PATCH 2/5] rust: block: introduce `kernel::block::bio` module Andreas Hindborg
2024-03-13 11:05 ` [RFC PATCH 3/5] rust: block: allow `hrtimer::Timer` in `RequestData` Andreas Hindborg
2024-03-23 10:51 ` Benno Lossin
2024-04-02 12:43 ` Andreas Hindborg
2024-03-13 11:05 ` [RFC PATCH 4/5] rust: block: add rnull, Rust null_blk implementation Andreas Hindborg
2024-03-23 11:33 ` Benno Lossin
2024-04-02 12:52 ` Andreas Hindborg
2024-04-02 22:35 ` Benno Lossin
2024-04-03 9:47 ` Andreas Hindborg
2024-04-03 10:29 ` Benno Lossin
2024-03-13 11:05 ` [RFC PATCH 5/5] MAINTAINERS: add entry for Rust block device driver API Andreas Hindborg
2024-03-13 18:02 ` [RFC PATCH 0/5] Rust block device driver API and null block driver Bart Van Assche
2024-03-13 18:22 ` Boqun Feng
2024-03-13 19:03 ` Andreas Hindborg
2024-03-13 19:11 ` Bart Van Assche
2024-03-13 19:12 ` Matthew Wilcox
2024-03-14 12:14 ` Philipp Stanner
2024-03-14 17:03 ` Bart Van Assche
2024-03-14 17:16 ` Conor Dooley
2024-03-14 17:43 ` Andreas Hindborg
2024-03-17 2:50 ` Matthew Wilcox
2024-03-17 7:09 ` Andreas Hindborg
2024-03-17 21:34 ` Matthew Wilcox
-- strict thread matches above, loose matches on Subject: below --
2024-03-22 23:40 [RFC PATCH 1/5] rust: block: introduce `kernel::block::mq` module Benno Lossin
2024-03-23 6:32 ` Andreas Hindborg
2024-04-02 23:09 ` Benno Lossin
2024-04-03 8:46 ` Andreas Hindborg
2024-04-03 19:37 ` Benno Lossin
2024-04-04 5:44 ` Andreas Hindborg
2024-04-04 8:46 ` Benno Lossin
2024-04-04 9:30 ` Andreas Hindborg
2024-04-04 13:20 ` Benno Lossin
2024-04-05 8:43 ` Andreas Hindborg
2024-04-05 9:40 ` Benno Lossin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87il1nqtak.fsf@metaspace.dk \
--to=nmi@metaspace.dk \
--cc=1182282462@bupt.edu.cn \
--cc=Damien.LeMoal@wdc.com \
--cc=Niklas.Cassel@wdc.com \
--cc=a.hindborg@samsung.com \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=axboe@kernel.dk \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=bvanassche@acm.org \
--cc=chaitanyak@nvidia.com \
--cc=da.gomez@samsung.com \
--cc=gary@garyguo.net \
--cc=gost.dev@samsung.com \
--cc=gregkh@linuxfoundation.org \
--cc=hare@suse.de \
--cc=hch@lst.de \
--cc=j.granados@samsung.com \
--cc=kbusch@kernel.org \
--cc=kernel@pankajraghav.com \
--cc=linux-block@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lsf-pc@lists.linux-foundation.org \
--cc=mcgrof@kernel.org \
--cc=miguel.ojeda.sandonis@gmail.com \
--cc=ming.lei@redhat.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=sergio.collado@gmail.com \
--cc=wedsonaf@gmail.com \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).