[PATCH 11/15] [media] v4l2: disable filesystem-dax mapping support

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

 



V4L2 memory registrations are incompatible with filesystem-dax that
needs the ability to revoke dma access to a mapping at will, or
otherwise allow the kernel to wait for completion of DMA. The
filesystem-dax implementation breaks the traditional solution of
truncate of active file backed mappings since there is no page-cache
page we can orphan to sustain ongoing DMA.

If v4l2 wants to support long lived DMA mappings it needs to arrange to
hold a file lease or use some other mechanism so that the kernel can
coordinate revoking DMA access when the filesystem needs to truncate
mappings.

Reported-by: Jan Kara <jack@xxxxxxx>
Cc: Mauro Carvalho Chehab <mchehab@xxxxxxxxxx>
Cc: linux-media@xxxxxxxxxxxxxxx
Cc: <stable@xxxxxxxxxxxxxxx>
Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx>
---
 drivers/media/v4l2-core/videobuf-dma-sg.c |   39 ++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
index 0b5c43f7e020..37a4ae61b2c0 100644
--- a/drivers/media/v4l2-core/videobuf-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
@@ -155,8 +155,9 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
 			int direction, unsigned long data, unsigned long size)
 {
 	unsigned long first, last;
-	int err, rw = 0;
+	int err, rw = 0, i, nr_pages;
 	unsigned int flags = FOLL_FORCE;
+	struct vm_area_struct **vmas = NULL;
 
 	dma->direction = direction;
 	switch (dma->direction) {
@@ -179,6 +180,16 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
 	if (NULL == dma->pages)
 		return -ENOMEM;
 
+	if (IS_ENABLED(CONFIG_FS_DAX)) {
+		vmas = kmalloc(dma->nr_pages * sizeof(struct vm_area_struct *),
+				GFP_KERNEL);
+		if (NULL == vmas) {
+			kfree(dma->pages);
+			dma->pages = NULL;
+			return -ENOMEM;
+		}
+	}
+
 	if (rw == READ)
 		flags |= FOLL_WRITE;
 
@@ -186,7 +197,31 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
 		data, size, dma->nr_pages);
 
 	err = get_user_pages(data & PAGE_MASK, dma->nr_pages,
-			     flags, dma->pages, NULL);
+			     flags, dma->pages, vmas);
+	nr_pages = err;
+
+	for (i = 0; vmas && i < nr_pages; i++) {
+		struct vm_area_struct *vma = vmas[i];
+		struct inode *inode;
+
+		if (!vma_is_dax(vma))
+			continue;
+
+		/* device-dax is safe for long-lived v4l2 mappings... */
+		inode = file_inode(vma->vm_file);
+		if (inode->i_mode == S_IFCHR)
+			continue;
+
+		/* ...filesystem-dax is not. */
+		err = -EOPNOTSUPP;
+		break;
+
+		/*
+		 * FIXME: add a 'with lease' mechanism for v4l2 to
+		 * obtain time bounded access to filesytem-dax mappings
+		 */
+	}
+	kfree(vmas);
 
 	if (err != dma->nr_pages) {
 		dma->nr_pages = (err >= 0) ? err : 0;




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]