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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxxxxxxx>
Cc: Laura Abbott <labbott@xxxxxxxxxx>
Cc: Sumit Semwal <sumit.semwal@xxxxxxxxxx>
Cc: Daniel Vetter <daniel.vetter@xxxxxxxx>
Cc: Sean Paul <seanpaul@xxxxxxxxxxxx>
---
 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;
 }
 
 /**
@@ -318,6 +394,8 @@ static const struct file_operations dma_buf_fops = {
 	.release	= dma_buf_release,
 	.mmap		= dma_buf_mmap_internal,
 	.llseek		= dma_buf_llseek,
+	.read		= dma_buf_read,
+	.write		= dma_buf_write,
 	.poll		= dma_buf_poll,
 	.unlocked_ioctl	= dma_buf_ioctl,
 #ifdef CONFIG_COMPAT
-- 
2.11.0

_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/dri-devel




[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux