usb: gadget: functionfs: Wait for fences before enqueueing DMABUF
authorPaul Cercueil <paul@crapouillou.net>
Tue, 2 Apr 2024 11:09:51 +0000 (13:09 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 4 Apr 2024 13:20:30 +0000 (15:20 +0200)
Instead of bailing when fences have already been installed on the
DMABUF, wait for them (with a timeout) when doing a blocking operation.

This fixes the issue where userspace would submit a DMABUF with fences
already installed, with the (correct) expectation that it would just
work.

Fixes: 7b07a2a7ca02 ("usb: gadget: functionfs: Add DMABUF import interface")
Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Link: https://lore.kernel.org/r/20240402110951.16376-3-paul@crapouillou.net
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/function/f_fs.c

index 70e8532127ad5a34c951d62f27433193cf6b9622..f855f1fc8e5e14d253a61382a692a9173c2e2c26 100644 (file)
@@ -46,6 +46,8 @@
 
 #define FUNCTIONFS_MAGIC       0xa647361 /* Chosen by a honest dice roll ;) */
 
+#define DMABUF_ENQUEUE_TIMEOUT_MS 5000
+
 MODULE_IMPORT_NS(DMA_BUF);
 
 /* Reference counter handling */
@@ -1580,9 +1582,11 @@ static int ffs_dmabuf_transfer(struct file *file,
        struct usb_request *usb_req;
        enum dma_resv_usage resv_dir;
        struct dma_buf *dmabuf;
+       unsigned long timeout;
        struct ffs_ep *ep;
        bool cookie;
        u32 seqno;
+       long retl;
        int ret;
 
        if (req->flags & ~USB_FFS_DMABUF_TRANSFER_MASK)
@@ -1616,17 +1620,14 @@ static int ffs_dmabuf_transfer(struct file *file,
                goto err_attachment_put;
 
        /* Make sure we don't have writers */
-       if (!dma_resv_test_signaled(dmabuf->resv, DMA_RESV_USAGE_WRITE)) {
-               pr_vdebug("FFS WRITE fence is not signaled\n");
-               ret = -EBUSY;
-               goto err_resv_unlock;
-       }
-
-       /* If we're writing to the DMABUF, make sure we don't have readers */
-       if (epfile->in &&
-           !dma_resv_test_signaled(dmabuf->resv, DMA_RESV_USAGE_READ)) {
-               pr_vdebug("FFS READ fence is not signaled\n");
-               ret = -EBUSY;
+       timeout = nonblock ? 0 : msecs_to_jiffies(DMABUF_ENQUEUE_TIMEOUT_MS);
+       retl = dma_resv_wait_timeout(dmabuf->resv,
+                                    dma_resv_usage_rw(epfile->in),
+                                    true, timeout);
+       if (retl == 0)
+               retl = -EBUSY;
+       if (retl < 0) {
+               ret = (int)retl;
                goto err_resv_unlock;
        }