From: Fred Griffoul <[email protected]>

dma_buf_dynamic_attach() requires a struct device: the device for which
the buffer is mapped for DMA. Exporters may also check it before they
accept the attachment. An importer that does not perform DMA has no
such device. iommufd already attaches with a global placeholder device
for this reason. KVM would need one too, although it only needs to know
where the memory is so that it can map it into a guest.

Allow @dev to be NULL for a dynamic importer. Such an importer learns
where the memory is from get_phys() and builds its own mappings. It
must not map the attachment for DMA, and dma_buf_map_attachment()
refuses an attachment without a device. An exporter that needs a device
to answer can refuse the attachment in its attach op, as it can for any
other reason.

Signed-off-by: Fred Griffoul <[email protected]>
---
 drivers/dma-buf/dma-buf.c      | 15 +++++++++++++--
 include/trace/events/dma_buf.h |  2 +-
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index e7010163eb2f..3d43b529a523 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -1007,6 +1007,13 @@ dma_buf_pin_on_map(struct dma_buf_attachment *attach)
  * Note that this can fail if the backing storage of @dmabuf is in a place not
  * accessible to @dev, and cannot be moved to a more suitable place. This is
  * indicated with the error code -EBUSY.
+ *
+ * @dev may be NULL for a dynamic importer that is not a DMA master: one that
+ * only asks the exporter where the memory is, through &dma_buf_ops.get_phys,
+ * and builds its own mappings from the answer.  Such an importer must never
+ * call dma_buf_map_attachment(), and an exporter that needs a device to
+ * answer (a peer-to-peer check, say) refuses the attachment in its
+ * &dma_buf_ops.attach.
  */
 struct dma_buf_attachment *
 dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev,
@@ -1016,7 +1023,7 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct 
device *dev,
        struct dma_buf_attachment *attach;
        int ret;
 
-       if (WARN_ON(!dmabuf || !dev))
+       if (WARN_ON(!dmabuf || (!dev && !importer_ops)))
                return ERR_PTR(-EINVAL);
 
        attach = kzalloc_obj(*attach);
@@ -1175,6 +1182,9 @@ struct sg_table *dma_buf_map_attachment(struct 
dma_buf_attachment *attach,
 
        if (WARN_ON(!attach || !attach->dmabuf))
                return ERR_PTR(-EINVAL);
+       /* An importer without a device cannot be a DMA master. */
+       if (WARN_ON(!attach->dev))
+               return ERR_PTR(-EINVAL);
 
        dma_resv_assert_held(attach->dmabuf->resv);
 
@@ -1847,7 +1857,8 @@ static int dma_buf_debug_show(struct seq_file *s, void 
*unused)
                attach_count = 0;
 
                list_for_each_entry(attach_obj, &buf_obj->attachments, node) {
-                       seq_printf(s, "\t%s\n", dev_name(attach_obj->dev));
+                       seq_printf(s, "\t%s\n", attach_obj->dev ?
+                                  dev_name(attach_obj->dev) : "none");
                        attach_count++;
                }
                dma_resv_unlock(buf_obj->resv);
diff --git a/include/trace/events/dma_buf.h b/include/trace/events/dma_buf.h
index 3bb88d05bcc8..7cabca53b798 100644
--- a/include/trace/events/dma_buf.h
+++ b/include/trace/events/dma_buf.h
@@ -40,7 +40,7 @@ DECLARE_EVENT_CLASS(dma_buf_attach_dev,
        TP_ARGS(dmabuf, attach, is_dynamic, dev),
 
        TP_STRUCT__entry(
-               __string(       dev_name,                       dev_name(dev))
+               __string(dev_name, dev ? dev_name(dev) : "none")
                __string(       exp_name,                       
dmabuf->exp_name)
                __field(        size_t,                         size)
                __field(        ino_t,                          ino)
-- 
2.47.3


Reply via email to