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

[PATCH v1 2/3] dma-buf: add dma buffer release notifier callback



Add posibility to register callback on dma-buffer which is
called before dma_buf->ops->release call.
This helps when external user of the dma buffer should be notified
before buffer releases without changing dma-buf ops. This is needed when
external dma buffer is used as backing storage for gntdev refs export
and grant refs should be unmapped before dma buffer release.

Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@xxxxxxxx>
---
 drivers/dma-buf/dma-buf.c | 44 +++++++++++++++++++++++++++++++++++++++
 include/linux/dma-buf.h   | 15 +++++++++++++
 2 files changed, 59 insertions(+)

diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index efb4990b29e1..3e663ef92e1f 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -25,6 +25,7 @@
 #include <linux/dma-resv.h>
 #include <linux/mm.h>
 #include <linux/mount.h>
+#include <linux/notifier.h>
 #include <linux/pseudo_fs.h>
 
 #include <uapi/linux/dma-buf.h>
@@ -57,6 +58,46 @@ static char *dmabuffs_dname(struct dentry *dentry, char 
*buffer, int buflen)
                             dentry->d_name.name, ret > 0 ? name : "");
 }
 
+int dma_buf_register_release_notifier(struct dma_buf *dmabuf,
+                       ext_release_notifier_cb ext_release_cb, void *priv)
+{
+       int ret = 0;
+
+       spin_lock(&dmabuf->ext_release_lock);
+
+       if (dmabuf->ext_release_cb) {
+               ret = -EEXIST;
+               goto unlock;
+       }
+
+       dmabuf->ext_release_cb = ext_release_cb;
+       dmabuf->ext_release_priv = priv;
+ unlock:
+       spin_unlock(&dmabuf->ext_release_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dma_buf_register_release_notifier);
+
+void dma_buf_unregister_release_notifier(struct dma_buf *dmabuf)
+{
+       spin_lock(&dmabuf->ext_release_lock);
+       dmabuf->ext_release_cb = NULL;
+       spin_unlock(&dmabuf->ext_release_lock);
+}
+EXPORT_SYMBOL_GPL(dma_buf_unregister_release_notifier);
+
+static void dma_buf_call_release_notifier(struct dma_buf *dmabuf)
+{
+       if (!dmabuf->ext_release_cb)
+               return;
+
+       spin_lock(&dmabuf->ext_release_lock);
+       dmabuf->ext_release_cb(dmabuf, dmabuf->ext_release_priv);
+       spin_unlock(&dmabuf->ext_release_lock);
+
+       dma_buf_unregister_release_notifier(dmabuf);
+}
+
 static void dma_buf_release(struct dentry *dentry)
 {
        struct dma_buf *dmabuf;
@@ -75,6 +116,8 @@ static void dma_buf_release(struct dentry *dentry)
        BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
 
        dma_buf_stats_teardown(dmabuf);
+       dma_buf_call_release_notifier(dmabuf);
+
        dmabuf->ops->release(dmabuf);
 
        if (dmabuf->resv == (struct dma_resv *)&dmabuf[1])
@@ -642,6 +685,7 @@ struct dma_buf *dma_buf_export(const struct 
dma_buf_export_info *exp_info)
        init_waitqueue_head(&dmabuf->poll);
        dmabuf->cb_in.poll = dmabuf->cb_out.poll = &dmabuf->poll;
        dmabuf->cb_in.active = dmabuf->cb_out.active = 0;
+       spin_lock_init(&dmabuf->ext_release_lock);
 
        if (!resv) {
                resv = (struct dma_resv *)&dmabuf[1];
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index 71731796c8c3..6282d56ac040 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -287,6 +287,8 @@ struct dma_buf_ops {
        void (*vunmap)(struct dma_buf *dmabuf, struct iosys_map *map);
 };
 
+typedef void (*ext_release_notifier_cb)(struct dma_buf *dmabuf, void *priv);
+
 /**
  * struct dma_buf - shared buffer object
  *
@@ -432,6 +434,15 @@ struct dma_buf {
         */
        struct dma_resv *resv;
 
+       /** @ext_release_cb notififier callback to call on release */
+       ext_release_notifier_cb ext_release_cb;
+
+       /** @ext_release_priv private data for callback */
+       void *ext_release_priv;
+
+       /** @ext_release_lock spinlock for ext_notifier helper */
+       spinlock_t ext_release_lock;
+
        /** @poll: for userspace poll support */
        wait_queue_head_t poll;
 
@@ -632,4 +643,8 @@ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *,
                 unsigned long);
 int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map);
 void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map);
+
+int dma_buf_register_release_notifier(struct dma_buf *dmabuf,
+                ext_release_notifier_cb ext_release_cb, void *priv);
+void dma_buf_unregister_release_notifier(struct dma_buf *dmabuf);
 #endif /* __DMA_BUF_H__ */
-- 
2.25.1



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.