[RFC 05/13] v4l: vb2-dma-contig: add support for DMABUF exporting

Laurent Pinchart laurent.pinchart at ideasonboard.com
Mon May 7 06:27:36 PDT 2012


Hi Tomasz,

Sorry for the late reply, this one slipped through the cracks.

On Thursday 19 April 2012 12:42:12 Tomasz Stanislawski wrote:
> On 04/17/2012 04:08 PM, Laurent Pinchart wrote:
> > On Tuesday 10 April 2012 15:10:39 Tomasz Stanislawski wrote:
> >> This patch adds support for exporting a dma-contig buffer using
> >> DMABUF interface.
> >> 
> >> Signed-off-by: Tomasz Stanislawski <t.stanislaws at samsung.com>
> >> Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
> >> ---
> 
> [snip]
> 
> >> +static struct sg_table *vb2_dc_dmabuf_ops_map(
> >> +	struct dma_buf_attachment *db_attach, enum dma_data_direction dir)
> >> +{
> >> +	struct dma_buf *dbuf = db_attach->dmabuf;
> >> +	struct vb2_dc_buf *buf = dbuf->priv;
> >> +	struct vb2_dc_attachment *attach = db_attach->priv;
> >> +	struct sg_table *sgt;
> >> +	struct scatterlist *rd, *wr;
> >> +	int i, ret;
> > 
> > You can make i an unsigned int :-)
> 
> Right.. splitting declaration may be also a good idea :)
> 
> >> +
> >> +	/* return previously mapped sg table */
> >> +	if (attach)
> >> +		return &attach->sgt;
> > 
> > This effectively keeps the mapping around as long as the attachment
> > exists. We don't try to swap out buffers in V4L2 as is done in DRM at the
> > moment, so it might not be too much of an issue, but the behaviour of the
> > implementation will change if we later decide to map/unmap the buffers in
> > the map/unmap handlers. Do you think that could be a problem ?
> 
> I don't that it is a problem. If an importer calls dma_map_sg then caching
> sgt on an exporter side reduces a cost of an allocating and an
> initialization of sgt.
> 
> >> +
> >> +	attach = kzalloc(sizeof *attach, GFP_KERNEL);
> >> +	if (!attach)
> >> +		return ERR_PTR(-ENOMEM);
> > 
> > Why don't you allocate the vb2_dc_attachment here instead of
> > vb2_dc_dmabuf_ops_attach() ?
> 
> Good point.
> The attachment could be allocated at vb2_dc_attachment but all its
> fields would be uninitialized. I mean an empty sgt and an undefined
> dma direction. I decided to allocate the attachment in vb2_dc_dmabuf_ops_map
> because only than all information needed to create a valid attachment
> object are available.
> 
> The other solution might be the allocation at vb2_dc_attachment. The field
> dir would be set to DMA_NONE. If this filed is equal to DMA_NONE at
> vb2_dc_dmabuf_ops_map then sgt is allocated and mapped and direction field
> is updated. If value is not DMA_NONE then the sgt is reused.
> 
> Do you think that it is a good idea?

I think I would prefer that. It sounds more logical to allocate the attachment 
in the attach operation handler.

> >> +	sgt = &attach->sgt;
> >> +	attach->dir = dir;
> >> +
> >> +	/* copying the buf->base_sgt to attachment */
> > 
> > I would add an explanation regarding why you need to copy the SG list.
> > Something like.
> > 
> > "Copy the buf->base_sgt scatter list to the attachment, as we can't map
> > the same scatter list to multiple devices at the same time."
> 
> ok
> 
> >> +	ret = sg_alloc_table(sgt, buf->sgt_base->orig_nents, GFP_KERNEL);
> >> +	if (ret) {
> >> +		kfree(attach);
> >> +		return ERR_PTR(-ENOMEM);
> >> +	}
> >> +
> >> +	rd = buf->sgt_base->sgl;
> >> +	wr = sgt->sgl;
> >> +	for (i = 0; i < sgt->orig_nents; ++i) {
> >> +		sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
> >> +		rd = sg_next(rd);
> >> +		wr = sg_next(wr);
> >> +	}
> >> 
> >> +	/* mapping new sglist to the client */
> >> +	ret = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, dir);
> >> +	if (ret <= 0) {
> >> +		printk(KERN_ERR "failed to map scatterlist\n");
> >> +		sg_free_table(sgt);
> >> +		kfree(attach);
> >> +		return ERR_PTR(-EIO);
> >> +	}
> >> +
> >> +	db_attach->priv = attach;
> >> +
> >> +	return sgt;
> >> +}
> >> +
> >> +static void vb2_dc_dmabuf_ops_unmap(struct dma_buf_attachment
> >> *db_attach,
> >> +	struct sg_table *sgt, enum dma_data_direction dir)
> >> +{
> >> +	/* nothing to be done here */
> >> +}
> >> +
> >> +static void vb2_dc_dmabuf_ops_release(struct dma_buf *dbuf)
> >> +{
> >> +	/* drop reference obtained in vb2_dc_get_dmabuf */
> >> +	vb2_dc_put(dbuf->priv);
> > 
> > Shouldn't you set vb2_dc_buf::dma_buf to NULL here ? Otherwise the next
> > vb2_dc_get_dmabuf() call will return a DMABUF object that has been freed.
> 
> No.
> 
> The buffer object is destroyed at vb2_dc_put when reference count drops to
> 0. It happens could happen after only REQBUF(count=0) or on last close().
> The DMABUF object is created only for MMAP buffers. The DMABUF object is
> based only on results of dma_alloc_coherent and dma_get_pages (or its future
> equivalent). Therefore the DMABUF object is valid as long as the buffer is
> valid.

OK.

> Notice that dmabuf object could be created in vb2_dc_alloc. I moved it to
> vb2_dc_get_dmabuf to avoid a creation of an object that may not be used.
> 
> >> +}
> >> +
> >> +static struct dma_buf_ops vb2_dc_dmabuf_ops = {
> >> +	.attach = vb2_dc_dmabuf_ops_attach,
> >> +	.detach = vb2_dc_dmabuf_ops_detach,
> >> +	.map_dma_buf = vb2_dc_dmabuf_ops_map,
> >> +	.unmap_dma_buf = vb2_dc_dmabuf_ops_unmap,
> >> +	.release = vb2_dc_dmabuf_ops_release,
> >> +};
> >> +
> >> +static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv)
> >> +{
> >> +	struct vb2_dc_buf *buf = buf_priv;
> >> +	struct dma_buf *dbuf;
> >> +
> >> +	if (buf->dma_buf)
> >> +		return buf->dma_buf;
> > 
> > Can't there be a race condition here if the user closes the DMABUF file
> > handle before vb2 core calls dma_buf_fd() ?
> 
> The user cannot access the file until it is associated with a file
> descriptor. How can the user close it? Could you give me a more detailed
> description of this potential race condition?

Let's assume the V4L2 buffer has already been exported once. buf->dma_buf is 
set to a non-NULL value, and the application has an open file handle for the 
buffer. The application then tries to export the buffer a second time. 
vb2_dc_get_dmabuf() gets called, checks buf->dma_buf and returns it as it's 
non-NULL. Right after that, before the vb2 core calls dma_buf_fd() on the 
struct dma_buf, the application closes the file handle to the exported buffer. 
The struct dma_buf object gets freed, as the reference count drops to 0. The 
vb2 core will then try to call dma_buf_fd() on a dma_buf object that has been 
freed.

> >> +	/* dmabuf keeps reference to vb2 buffer */
> >> +	atomic_inc(&buf->refcount);
> >> +	dbuf = dma_buf_export(buf, &vb2_dc_dmabuf_ops, buf->size, 0);
> >> +	if (IS_ERR(dbuf)) {
> >> +		atomic_dec(&buf->refcount);
> >> +		return NULL;
> >> +	}
> >> +
> >> +	buf->dma_buf = dbuf;
> >> +
> >> +	return dbuf;
> >> +}

-- 
Regards,

Laurent Pinchart



More information about the dri-devel mailing list