From faedd820db96296eafbae83188f150d3cc45caea Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Mon, 20 Mar 2017 09:46:47 +0800 Subject: [PATCH] dma-buf: add release callback support Change-Id: Ibfb4ffe3d97fae0a27f20032fdfbc3cc561aa375 Signed-off-by: Mark Yao --- drivers/dma-buf/dma-buf.c | 46 +++++++++++++++++++++++++++++++++++++++ include/linux/dma-buf.h | 10 +++++++++ 2 files changed, 56 insertions(+) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 155c1464948e..15c0fbc817a5 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -36,6 +36,12 @@ static inline int is_dma_buf_file(struct file *); +struct dma_buf_callback { + struct list_head list; + void (*callback)(void *); + void *data; +}; + struct dma_buf_list { struct list_head head; struct mutex lock; @@ -46,6 +52,7 @@ static struct dma_buf_list db_list; static int dma_buf_release(struct inode *inode, struct file *file) { struct dma_buf *dmabuf; + struct dma_buf_callback *cb, *tmp; if (!is_dma_buf_file(file)) return -EINVAL; @@ -64,6 +71,13 @@ static int dma_buf_release(struct inode *inode, struct file *file) */ BUG_ON(dmabuf->cb_shared.active || dmabuf->cb_excl.active); + list_for_each_entry_safe(cb, tmp, &dmabuf->release_callbacks, list) { + if (cb->callback) + cb->callback(cb->data); + list_del(&cb->list); + kfree(cb); + } + dmabuf->ops->release(dmabuf); mutex_lock(&db_list.lock); @@ -266,6 +280,37 @@ static inline int is_dma_buf_file(struct file *file) return file->f_op == &dma_buf_fops; } +int dma_buf_set_release_callback(struct dma_buf *dmabuf, + void (*callback)(void *), void *data) +{ + struct dma_buf_callback *cb; + + if (WARN_ON(dma_buf_get_release_callback_data(dmabuf, callback))) + return -EINVAL; + + cb = kzalloc(sizeof(*cb), GFP_KERNEL); + if (!cb) + return -ENOMEM; + cb->callback = callback; + cb->data = data; + list_add_tail(&cb->list, &dmabuf->release_callbacks); + + return 0; +} + +void *dma_buf_get_release_callback_data(struct dma_buf *dmabuf, + void (*callback)(void *)) +{ + struct dma_buf_callback *cb, *tmp; + + list_for_each_entry_safe(cb, tmp, &dmabuf->release_callbacks, list) { + if (cb->callback == callback) + return cb->data; + } + + return NULL; +} + /** * dma_buf_export - Creates a new dma_buf, and associates an anon file * with this buffer, so it can be exported. @@ -341,6 +386,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) mutex_init(&dmabuf->lock); INIT_LIST_HEAD(&dmabuf->attachments); + INIT_LIST_HEAD(&dmabuf->release_callbacks); mutex_lock(&db_list.lock); list_add(&dmabuf->list_node, &db_list.head); diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index f98bd7068d55..d58bd33d6435 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -90,6 +90,9 @@ struct dma_buf_ops { * if the call would block. */ + int (*set_release_callback)(void (*release_callback)(void *data), + void *data); + void *(*get_release_callback_data)(void *callback); /* after final dma_buf_put() */ void (*release)(struct dma_buf *); @@ -125,6 +128,7 @@ struct dma_buf { size_t size; struct file *file; struct list_head attachments; + struct list_head release_callbacks; const struct dma_buf_ops *ops; /* mutex to serialize list manipulation, attach/detach and vmap/unmap */ struct mutex lock; @@ -209,6 +213,12 @@ static inline void get_dma_buf(struct dma_buf *dmabuf) get_file(dmabuf->file); } +int dma_buf_set_release_callback(struct dma_buf *dmabuf, + void (*callback)(void *), void *data); + +void *dma_buf_get_release_callback_data(struct dma_buf *dmabuf, + void (*callback)(void *)); + struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, struct device *dev); void dma_buf_detach(struct dma_buf *dmabuf, -- 2.34.1