[PATCH v2] dma-buf: Implement simple read/write vfs ops

Laura Abbott labbott at redhat.com
Wed Apr 12 19:57:00 UTC 2017


On 04/12/2017 12:38 PM, Chris Wilson wrote:
> On Wed, Apr 12, 2017 at 11:29:18AM -0700, Laura Abbott wrote:
>> On 04/07/2017 02:25 PM, Chris Wilson wrote:
>>> It is expected that processes will pass dma-buf fd between drivers, and
>>> only using the fd themselves for mmaping and synchronisation ioctls.
>>> However, it may be convenient for an application to read/write into the
>>> dma-buf, for instance a test case to check the internal
>>> dma_buf->ops->kmap interface. There may also be a small advantage to
>>> avoiding the mmap() for very simple/small operations.
>>>
>>> Note in particular, synchronisation with the device is left to the
>>> caller with an explicit DMA_BUF_IOCTL_SYNC, rather than done implicitly
>>> inside the read/write, so that the user can avoid synchronisation if
>>> they so choose.
>>>
>>> v2: Lots of little fixes, plus a real llseek() implements so that the
>>> first basic little test cases work!
>>>
>>> Testcase: igt/prime_rw
>>> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
>>> Cc: Laura Abbott <labbott at redhat.com>
>>> Cc: Sumit Semwal <sumit.semwal at linaro.org>
>>> Cc: Daniel Vetter <daniel.vetter at ffwll.ch>
>>> Cc: Sean Paul <seanpaul at chromium.org>
>>> ---
>>>  drivers/dma-buf/dma-buf.c | 108 +++++++++++++++++++++++++++++++++++++++-------
>>>  1 file changed, 93 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
>>> index 1ce7974a28a3..6e6e35c660c7 100644
>>> --- a/drivers/dma-buf/dma-buf.c
>>> +++ b/drivers/dma-buf/dma-buf.c
>>> @@ -100,28 +100,104 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
>>>  
>>>  static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
>>>  {
>>> -	struct dma_buf *dmabuf;
>>> -	loff_t base;
>>> +	struct dma_buf *dmabuf = file->private_data;
>>>  
>>>  	if (!is_dma_buf_file(file))
>>>  		return -EBADF;
>>>  
>>> -	dmabuf = file->private_data;
>>> +	return fixed_size_llseek(file, offset, whence, dmabuf->size);
>>> +}
>>>  
>>> -	/* only support discovering the end of the buffer,
>>> -	   but also allow SEEK_SET to maintain the idiomatic
>>> -	   SEEK_END(0), SEEK_CUR(0) pattern */
>>> -	if (whence == SEEK_END)
>>> -		base = dmabuf->size;
>>> -	else if (whence == SEEK_SET)
>>> -		base = 0;
>>> -	else
>>> -		return -EINVAL;
>>> +static ssize_t dma_buf_read(struct file *file,
>>> +			    char __user *ubuf, size_t remain,
>>> +			    loff_t *offset)
>>> +{
>>> +	struct dma_buf *dmabuf = file->private_data;
>>> +	unsigned long idx;
>>> +	unsigned int start;
>>> +	size_t total;
>>>  
>>> -	if (offset != 0)
>>> -		return -EINVAL;
>>> +	if (!is_dma_buf_file(file))
>>> +		return -EBADF;
>>> +
>>> +	total = 0;
>>> +	idx = *offset >> PAGE_SHIFT;
>>> +	start = offset_in_page(*offset);
>>> +	while (remain) {
>>> +		unsigned int len = min_t(size_t, remain, PAGE_SIZE - start);
>>> +		unsigned int copied;
>>> +		void *vaddr;
>>> +
>>> +		if (*offset >= dmabuf->size)
>>> +			return total;
>>> +
>>> +		vaddr = dma_buf_kmap(dmabuf, idx);
>>> +		if (!vaddr)
>>> +			return total ?: -EIO;
>>> +
>>> +		copied = copy_to_user(ubuf, vaddr + start, len);
>>> +		dma_buf_kunmap(dmabuf, idx, vaddr);
>>> +
>>> +		total += copied ?: len;
>>> +		if (copied) {
>>> +			*offset += copied;
>>> +			return total ?: -EFAULT;
>>> +		}
>>> +
>>> +		remain -= len;
>>> +		*offset += len;
>>> +		ubuf += len;
>>> +		start = 0;
>>> +		idx++;
>>> +	}
>>> +
>>> +	return total;
>>> +}
>>> +
>>> +static ssize_t dma_buf_write(struct file *file,
>>> +			     const char __user *ubuf, size_t remain,
>>> +			     loff_t *offset)
>>> +{
>>> +	struct dma_buf *dmabuf = file->private_data;
>>> +	unsigned long idx;
>>> +	unsigned int start;
>>> +	size_t total;
>>> +
>>> +	if (!is_dma_buf_file(file))
>>> +		return -EBADF;
>>> +
>>> +	total = 0;
>>> +	idx = *offset >> PAGE_SHIFT;
>>> +	start = offset_in_page(*offset);
>>> +	while (remain) {
>>> +		unsigned int len = min_t(size_t, remain, PAGE_SIZE - start);
>>> +		unsigned int copied;
>>> +		void *vaddr;
>>> +
>>> +		if (*offset >= dmabuf->size)
>>> +			return total;
>>> +
>>> +		vaddr = dma_buf_kmap(dmabuf, idx);
>>> +		if (!vaddr)
>>> +			return total ?: -EIO;
>>> +
>>> +		copied = copy_from_user(vaddr + start, ubuf, len);
>>> +		dma_buf_kunmap(dmabuf, idx, vaddr);
>>> +
>>> +		total += copied ?: len;
>>> +		if (copied) {
>>> +			*offset += copied;
>>> +			return total ?: -EFAULT;
>>> +		}
>>> +
>>> +		remain -= len;
>>> +		*offset += len;
>>> +		ubuf += len;
>>> +		start = 0;
>>> +		idx++;
>>> +	}
>>>  
>>> -	return base + offset;
>>> +	return total;
>>>  }
>>>  
>>
>> Both the read/write are missing the dma_buf_begin_cpu_access calls.
>> When I add those these seem to work well enough for a simple
>> test. I can add a real Tested-by for the next version.
> 
> Correct, that was intentional to leave synchronisation to be managed by
> the caller. It is easier to add synchronisation than take it away.
> -Chris
> 

Ah yes, that makes sense. This is what the sync ioctls were for in
the first place :). You can add

Tested-by: Laura Abbott <labbott at redhat.com>

Thanks,
Laura



More information about the dri-devel mailing list