Benno Lossin <benno.lossin@xxxxxxxxx> writes: [...] >>>> +impl<T: Operations> OperationsVTable<T> { >>>> + /// This function is called by the C kernel. A pointer to this function is >>>> + /// installed in the `blk_mq_ops` vtable for the driver. >>>> + /// >>>> + /// # Safety >>>> + /// >>>> + /// - The caller of this function must ensure `bd` is valid >>>> + /// and initialized. The pointees must outlive this function. >>> >>> Until when do the pointees have to be alive? "must outlive this >>> function" could also be the case if the pointees die immediately after >>> this function returns. >> >> It should not be plural. What I intended to communicate is that what >> `bd` points to must be valid for read for the duration of the function >> call. I think that is what "The pointee must outlive this function" >> states? Although when we talk about lifetime of an object pointed to by >> a pointer, I am not sure about the correct way to word this. Do we talk >> about the lifetime of the pointer or the lifetime of the pointed to >> object (the pointee). We should not use the same wording for the pointer >> and the pointee. >> >> How about: >> >> /// - The caller of this function must ensure that the pointee of `bd` is >> /// valid for read for the duration of this function. > > But this is not enough for it to be sound, right? You create an `ARef` > from `bd.rq`, which potentially lives forever. You somehow need to > require that the pointer `bd` stays valid for reads and (synchronized) > writes until the request is ended (probably via `blk_mq_end_request`). The statement does not say anything about `*((*bd).rq)`. `*bd` needs to be valid only for the duration of the function. It carries a pointer to a `struct request` in the `rq` field. The pointee of that pointer must be exclusively owned by the driver until the request is done. Maybe like this: # Safety - The caller of this function must ensure that the pointee of `bd` is valid for read for the duration of this function. - This function must be called for an initialized and live `hctx`. That is, `Self::init_hctx_callback` was called and `Self::exit_hctx_callback()` was not yet called. - `(*bd).rq` must point to an initialized and live `bindings:request`. That is, `Self::init_request_callback` was called but `Self::exit_request_callback` was not yet called for the request. - `(*bd).rq` must be owned by the driver. That is, the block layer must promise to not access the request until the driver calls `bindings::blk_mq_end_request` for the request. [...] >>>> + /// This function is called by the C kernel. A pointer to this function is >>>> + /// installed in the `blk_mq_ops` vtable for the driver. >>>> + /// >>>> + /// # Safety >>>> + /// >>>> + /// This function may only be called by blk-mq C infrastructure. `set` must > > `set` doesn't exist (`_set` does), you are also not using this > requirement. Would be nice if there was a way in `rustdoc` no name arguments explicitly. > >>>> + /// point to an initialized `TagSet<T>`. >>>> + unsafe extern "C" fn init_request_callback( >>>> + _set: *mut bindings::blk_mq_tag_set, >>>> + rq: *mut bindings::request, >>>> + _hctx_idx: core::ffi::c_uint, >>>> + _numa_node: core::ffi::c_uint, >>>> + ) -> core::ffi::c_int { >>>> + from_result(|| { >>>> + // SAFETY: The `blk_mq_tag_set` invariants guarantee that all >>>> + // requests are allocated with extra memory for the request data. >>> >>> What guarantees that the right amount of memory has been allocated? >>> AFAIU that is guaranteed by the `TagSet` (but there is no invariant). >> >> It is by C API contract. `TagSet`::try_new` (now `new`) writes >> `cmd_size` into the `struct blk_mq_tag_set`. That is picked up by >> `blk_mq_alloc_tag_set` to allocate the right amount of space for each request. >> >> The invariant here is on the C type. Perhaps the wording is wrong. I am >> not exactly sure how to express this. How about this: >> >> // SAFETY: We instructed `blk_mq_alloc_tag_set` to allocate requests >> // with extra memory for the request data when we called it in >> // `TagSet::new`. > > I think you need a safety requirement on the function: `rq` points to a > valid `Request`. Then you could just use `Request::wrapper_ptr` instead > of the line below. I cannot require `rq` to point to a valid `Request`, because that would require the private data area to already be initialized as a valid `RequestDataWrapper`. Using the `wrapper_ptr` is good 👍. How is this: /// # Safety /// /// - This function may only be called by blk-mq C infrastructure. /// - `_set` must point to an initialized `TagSet<T>`. /// - `rq` must point to an initialized `bindings::request`. /// - The allocation pointed to by `rq` must be at the size of `Request` /// plus the size of `RequestDataWrapper`. BR Andreas