On 5/13/26 04:55, Deepanshu Kartikey wrote:
> On Tue, May 12, 2026 at 12:04 PM Dmitry Osipenko
> <dmitry.osipenko(a)collabora.com> wrote:
>>
>> I'm getting lockup with this patch applied and now see that
>> virtio_gpu_resource_flush() also locks BO.
>>
>> Easiest option might be to add uninterruptible variant of
>> virtio_gpu_array_lock_resv(). Could you please try it for v3?
>>
>> --
>> Best regards,
>> Dmitry
>
> Hi Dmitry,
>
> Thanks for testing and catching the lockup. Before I send v3, want
> to confirm the approach:
>
> 1. Revert v2's prepare_fb / cleanup_fb / plane_state changes;
> keep the lock acquisition inside cursor_plane_update like
> the original code.
>
> 2. Add virtio_gpu_array_lock_resv_uninterruptible() in
> virtgpu_gem.c, mirroring the existing helper but using
> dma_resv_lock() instead of dma_resv_lock_interruptible() on
> the nents==1 path. Declare it in virtgpu_drv.h.
>
> 3. In cursor_plane_update, call the new helper and check its
> return. The signal path is closed; -ENOMEM from
> dma_resv_reserve_fences() remains and is handled by freeing
> objs and skipping the cursor update for that frame.
>
> A skipped cursor frame on ENOMEM is the remaining failure mode in
> .atomic_update; this avoids the lockup with virtio_gpu_resource_flush()
> that v2's broader lock scope caused.
>
> Does that match what you had in mind?
Sounds good. The virtio_gpu_resource_flush() also should be updated to
use uninterruptible() variant.
--
Best regards,
Dmitry
> + union {
> + struct bio_vec *bi_io_vec;
> + /* Driver specific dma map, present only with BIO_DMABUF_MAP */
> + struct io_dmabuf_map *dmabuf_map;
> + };
... and please add the bi_ prefix we're using for all (well except for
one oddity) fields in struct bio.
On Wed, Apr 29, 2026 at 04:25:52PM +0100, Pavel Begunkov wrote:
> Add a trivial implementation of the create_dmabuf_token call for
> block devices that forwards the call to a new blk-mq callback if it's
> available.
This should go into block_device_operations as there is nothing blk-mq
specific about this. I.e. even if this patchset doesn't handle stacking
drivers yet, it should be easy enough to add them in the future.
Naming and placement:
This is about dma-buf based I/O. So I'd expect it to be named dma-buf-io
and no io-dmabuf, and live in drivers/dma-buf and not the unrelated lib/.
But I'd like to hear from the dma-buf maintainers about that.
Config option: as this unconditionally when DMA_SHARED_BUFFER is enabled,
why does it need a separate config option?
Interface: io_dmabuf_token_create / ->create_dmabuf_token filling
in a structure allocated by the caller feels odd. My gut feeling
would be to move most of io_dmabuf_token_create into a helper called
by ->create_dmabuf_token so that the token is allocated in the
driver data structure and returned from create_dmabuf_token.
> + if (!bio_flagged(bio_src, BIO_DMABUF_MAP)) {
> + bio->bi_io_vec = bio_src->bi_io_vec;
> + } else {
> + bio->dmabuf_map = bio_src->dmabuf_map;
> + bio_set_flag(bio, BIO_DMABUF_MAP);
> + }
This is backwards, please avoid pointless negations:
if (bio_flagged(bio_src, BIO_DMABUF_MAP)) {
bio->dmabuf_map = bio_src->dmabuf_map;
bio_set_flag(bio, BIO_DMABUF_MAP);
} else {
bio->bi_io_vec = bio_src->bi_io_vec;
}
> + if (bio_flagged(bio, BIO_DMABUF_MAP)) {
> + nsegs = 1;
> +
> + if ((bio->bi_iter.bi_bvec_done & lim->dma_alignment) ||
> + (bio->bi_iter.bi_size & len_align_mask))
> + return -EINVAL;
> + if (bio->bi_iter.bi_size > max_bytes) {
> + bytes = max_bytes;
> + goto split;
> + }
Please add a comment explaining why nsegs is always 1 here.
> @@ -424,7 +424,8 @@ static inline struct bio *__bio_split_to_limits(struct bio *bio,
> switch (bio_op(bio)) {
> case REQ_OP_READ:
> case REQ_OP_WRITE:
> - if (bio_may_need_split(bio, lim))
> + if (bio_may_need_split(bio, lim) ||
> + bio_flagged(bio, BIO_DMABUF_MAP))
> return bio_split_rw(bio, lim, nr_segs);
The BIO_DMABUF_MAP check should go into bio_may_need_split.
> +static inline void bio_advance_iter_dmabuf_map(struct bvec_iter *iter,
> + unsigned int bytes)
> +{
> + iter->bi_bvec_done += bytes;
> + iter->bi_size -= bytes;
> +}
> +
> static inline void bio_advance_iter(const struct bio *bio,
> struct bvec_iter *iter, unsigned int bytes)
> {
> iter->bi_sector += bytes >> 9;
>
> - if (bio_no_advance_iter(bio))
> + if (bio_no_advance_iter(bio)) {
> iter->bi_size -= bytes;
> - else
> + } else if (bio_flagged(bio, BIO_DMABUF_MAP)) {
> + bio_advance_iter_dmabuf_map(iter, bytes);
This is a bit of a mess. You're using bi_bvec_done for something that
is not bvec_done, which makes the naming very confusing. That is even
more confusing than the existing usage, which isn't great. Also we
add yet another conditional to heavily inlined code. I'd suggest
the following:
- add a prep patch to rename bi_bvec_done to bi_offset, as even for
the existing usage it is the offset into the current bio_vec as
much as it is the count of byes done, as those must be the same
and it is used both ways
- add a prep patch to also increase bi_offset for bio_no_advance_iter.
It is not actually use there, but incrementing it is harmless and
this will avoid a new special case
- please also documet this new usage in the commet in struct bvec_iter.
- then just add the dma buf mapping to the bio_no_advance_iter condition
- figure out what to do about dm_bio_rewind_iter, which pokes into these
things that really should be block layer internal
> }
> @@ -391,7 +403,7 @@ static inline void bio_wouldblock_error(struct bio *bio)
> */
> static inline int bio_iov_vecs_to_alloc(struct iov_iter *iter, int max_segs)
> {
> - if (iov_iter_is_bvec(iter))
> + if (iov_iter_is_bvec(iter) || iov_iter_is_dmabuf_map(iter))
> return 0;
> return iov_iter_npages(iter, max_segs);
> }
Please update the comment for this helper.
> @@ -322,6 +327,7 @@ enum {
> BIO_REMAPPED,
> BIO_ZONE_WRITE_PLUGGING, /* bio handled through zone write plugging */
> BIO_EMULATES_ZONE_APPEND, /* bio emulates a zone append operation */
> + BIO_DMABUF_MAP, /* Using premmaped dma buffers */
Shouldn't this be a REQ_ flag as we should never mix and match bios with
and without this flag in a single request?
On Wed, Apr 29, 2026 at 04:25:49PM +0100, Pavel Begunkov wrote:
> To quote Cristoph: "Historically __bio_clone itself does not clone the
It's Christoph.
> payload, just the bio. But we got rid of the callers that want to clone
> a bio but not the payload long time ago". So let's move ->bi_io_vec
> assignment into __bio_clone(), so we have a single point where it's set.
but this he-said, she-said is totally irrelevant.
Please state here why this is useful/important, which matters for anyone
trying to understand the code in the future.
On Wed, Apr 29, 2026 at 04:25:48PM +0100, Pavel Begunkov wrote:
> Introduce a new iterator type for dmabuf maps. The map in an opaque
> object with internals and format specific to the subsystem / driver, and
> only it can use that subsystem / driver for issuing IO. The task of the
> middle layers is to pass the map / iterator further down, maybe doing
> basic splitting and length checking. The iterator can only be used by
> operations of the file the associated map was created for.
Nice, this ended up way simpler than what I would have imagined.
Reviewed-by: Christoph Hellwig <hch(a)lst.de>
On Thu, Apr 30, 2026 at 07:33:39PM +0100, Pavel Begunkov wrote:
>> Then the patch should probably define the full interface and not just add the callback here and then the structure in a follow up patch.
>
> I strongly prefer splitting patches so that they touch one tree at
> a time whenever possible. tbh, I don't see much of a problem it being
> not defined as it's just forwarded in first patches, but I can shuffle
> it around in the series so that definitions come first.
file operations without users are pointless. This really should go
with "lib: add dmabuf token infrastructure" as it is the only way for
the reviewer to make any sense of it. I'll move my discussion of the
interface there for that reason.