diff mbox

[v2,1/2] dma-buf: add reference counting for exporter module

Message ID 1344504982-30415-2-git-send-email-t.stanislaws@samsung.com
State New
Headers show

Commit Message

Tomasz Stanislawski Aug. 9, 2012, 9:36 a.m. UTC
This patch adds reference counting on a module that exported dma-buf and
implements its operations. This prevents the module from being unloaded while
DMABUF file is in use.

Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Acked-by: Sumit Semwal <sumit.semwal@linaro.org>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
CC: linux-doc@vger.kernel.org
---
 Documentation/dma-buf-sharing.txt |    3 ++-
 drivers/base/dma-buf.c            |    9 ++++++++-
 include/linux/dma-buf.h           |    2 ++
 3 files changed, 12 insertions(+), 2 deletions(-)

Comments

gregkh@linuxfoundation.org Aug. 9, 2012, 2:23 p.m. UTC | #1
On Thu, Aug 09, 2012 at 11:36:21AM +0200, Tomasz Stanislawski wrote:
> This patch adds reference counting on a module that exported dma-buf and
> implements its operations. This prevents the module from being unloaded while
> DMABUF file is in use.

Why force all of the modules to be changed "by hand", and not just do
this automatically by changing the register function to include the
THIS_MODULE macro in it?  Much like the pci_register_driver() function
is implemented in include/linux/pci.h?

That makes it impossible for driver authors to get it wrong, which is
always a good sign of a correct api.

thanks,

greg k-h
Tomasz Stanislawski Aug. 9, 2012, 2:54 p.m. UTC | #2
Hi Greg,

On 08/09/2012 04:23 PM, Greg KH wrote:
> On Thu, Aug 09, 2012 at 11:36:21AM +0200, Tomasz Stanislawski wrote:
>> This patch adds reference counting on a module that exported dma-buf and
>> implements its operations. This prevents the module from being unloaded while
>> DMABUF file is in use.
> 
> Why force all of the modules to be changed "by hand", and not just do
> this automatically by changing the register function to include the
> THIS_MODULE macro in it?  Much like the pci_register_driver() function
> is implemented in include/linux/pci.h?

Thank you for the hint.

The owner field belongs to dma_buf_ops structure that is often a 'const'
entity. Therefore owner field would have to be moved to 'struct dma_buf'
to avoid 'deconstification' issues.

Regards,
Tomasz Stanislawski

> 
> That makes it impossible for driver authors to get it wrong, which is
> always a good sign of a correct api.
> 
> thanks,
> 
> greg k-h
>
diff mbox

Patch

diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt
index ad86fb8..2613057 100644
--- a/Documentation/dma-buf-sharing.txt
+++ b/Documentation/dma-buf-sharing.txt
@@ -49,7 +49,8 @@  The dma_buf buffer sharing API usage contains the following steps:
    The buffer exporter announces its wish to export a buffer. In this, it
    connects its own private buffer data, provides implementation for operations
    that can be performed on the exported dma_buf, and flags for the file
-   associated with this buffer.
+   associated with this buffer. The operations structure has owner field.
+   You should initialize this to THIS_MODULE in most cases.
 
    Interface:
       struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index c30f3e1..a1d9cab 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -27,6 +27,7 @@ 
 #include <linux/dma-buf.h>
 #include <linux/anon_inodes.h>
 #include <linux/export.h>
+#include <linux/module.h>
 
 static inline int is_dma_buf_file(struct file *);
 
@@ -40,6 +41,7 @@  static int dma_buf_release(struct inode *inode, struct file *file)
 	dmabuf = file->private_data;
 
 	dmabuf->ops->release(dmabuf);
+	module_put(dmabuf->ops->owner);
 	kfree(dmabuf);
 	return 0;
 }
@@ -105,9 +107,14 @@  struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
 		return ERR_PTR(-EINVAL);
 	}
 
+	if (!try_module_get(ops->owner))
+		return ERR_PTR(-ENOENT);
+
 	dmabuf = kzalloc(sizeof(struct dma_buf), GFP_KERNEL);
-	if (dmabuf == NULL)
+	if (dmabuf == NULL) {
+		module_put(ops->owner);
 		return ERR_PTR(-ENOMEM);
+	}
 
 	dmabuf->priv = priv;
 	dmabuf->ops = ops;
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index eb48f38..22953de 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -37,6 +37,7 @@  struct dma_buf_attachment;
 
 /**
  * struct dma_buf_ops - operations possible on struct dma_buf
+ * @owner: the module that implements dma_buf operations
  * @attach: [optional] allows different devices to 'attach' themselves to the
  *	    given buffer. It might return -EBUSY to signal that backing storage
  *	    is already allocated and incompatible with the requirements
@@ -70,6 +71,7 @@  struct dma_buf_attachment;
  * @vunmap: [optional] unmaps a vmap from the buffer
  */
 struct dma_buf_ops {
+	struct module *owner;
 	int (*attach)(struct dma_buf *, struct device *,
 			struct dma_buf_attachment *);