dmabuf: Add the capability to expose DMA-BUF stats in sysfs
[linux-2.6-microblaze.git] / drivers / dma-buf / dma-buf.c
index 511fe0d..d012140 100644 (file)
@@ -29,6 +29,8 @@
 #include <uapi/linux/dma-buf.h>
 #include <uapi/linux/magic.h>
 
+#include "dma-buf-sysfs-stats.h"
+
 static inline int is_dma_buf_file(struct file *);
 
 struct dma_buf_list {
@@ -79,6 +81,7 @@ static void dma_buf_release(struct dentry *dentry)
        if (dmabuf->resv == (struct dma_resv *)&dmabuf[1])
                dma_resv_fini(dmabuf->resv);
 
+       dma_buf_stats_teardown(dmabuf);
        module_put(dmabuf->owner);
        kfree(dmabuf->name);
        kfree(dmabuf);
@@ -580,6 +583,10 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
        file->f_mode |= FMODE_LSEEK;
        dmabuf->file = file;
 
+       ret = dma_buf_stats_setup(dmabuf);
+       if (ret)
+               goto err_sysfs;
+
        mutex_init(&dmabuf->lock);
        INIT_LIST_HEAD(&dmabuf->attachments);
 
@@ -589,6 +596,14 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
 
        return dmabuf;
 
+err_sysfs:
+       /*
+        * Set file->f_path.dentry->d_fsdata to NULL so that when
+        * dma_buf_release() gets invoked by dentry_ops, it exits
+        * early before calling the release() dma_buf op.
+        */
+       file->f_path.dentry->d_fsdata = NULL;
+       fput(file);
 err_dmabuf:
        kfree(dmabuf);
 err_module:
@@ -723,6 +738,7 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev,
 {
        struct dma_buf_attachment *attach;
        int ret;
+       unsigned int attach_uid;
 
        if (WARN_ON(!dmabuf || !dev))
                return ERR_PTR(-EINVAL);
@@ -748,8 +764,13 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev,
        }
        dma_resv_lock(dmabuf->resv, NULL);
        list_add(&attach->node, &dmabuf->attachments);
+       attach_uid = dma_buf_update_attach_uid(dmabuf);
        dma_resv_unlock(dmabuf->resv);
 
+       ret = dma_buf_attach_stats_setup(attach, attach_uid);
+       if (ret)
+               goto err_sysfs;
+
        /* When either the importer or the exporter can't handle dynamic
         * mappings we cache the mapping here to avoid issues with the
         * reservation object lock.
@@ -776,6 +797,7 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev,
                        dma_resv_unlock(attach->dmabuf->resv);
                attach->sgt = sgt;
                attach->dir = DMA_BIDIRECTIONAL;
+               dma_buf_update_attachment_map_count(attach, 1 /* delta */);
        }
 
        return attach;
@@ -792,6 +814,7 @@ err_unlock:
        if (dma_buf_is_dynamic(attach->dmabuf))
                dma_resv_unlock(attach->dmabuf->resv);
 
+err_sysfs:
        dma_buf_detach(dmabuf, attach);
        return ERR_PTR(ret);
 }
@@ -841,6 +864,7 @@ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
                        dma_resv_lock(attach->dmabuf->resv, NULL);
 
                __unmap_dma_buf(attach, attach->sgt, attach->dir);
+               dma_buf_update_attachment_map_count(attach, -1 /* delta */);
 
                if (dma_buf_is_dynamic(attach->dmabuf)) {
                        dmabuf->ops->unpin(attach);
@@ -854,6 +878,7 @@ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
        if (dmabuf->ops->detach)
                dmabuf->ops->detach(dmabuf, attach);
 
+       dma_buf_attach_stats_teardown(attach);
        kfree(attach);
 }
 EXPORT_SYMBOL_GPL(dma_buf_detach);
@@ -993,6 +1018,9 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
        }
 #endif /* CONFIG_DMA_API_DEBUG */
 
+       if (!IS_ERR(sg_table))
+               dma_buf_update_attachment_map_count(attach, 1 /* delta */);
+
        return sg_table;
 }
 EXPORT_SYMBOL_GPL(dma_buf_map_attachment);
@@ -1030,6 +1058,8 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
        if (dma_buf_is_dynamic(attach->dmabuf) &&
            !IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY))
                dma_buf_unpin(attach);
+
+       dma_buf_update_attachment_map_count(attach, -1 /* delta */);
 }
 EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
 
@@ -1469,6 +1499,12 @@ static inline void dma_buf_uninit_debugfs(void)
 
 static int __init dma_buf_init(void)
 {
+       int ret;
+
+       ret = dma_buf_init_sysfs_statistics();
+       if (ret)
+               return ret;
+
        dma_buf_mnt = kern_mount(&dma_buf_fs_type);
        if (IS_ERR(dma_buf_mnt))
                return PTR_ERR(dma_buf_mnt);
@@ -1484,5 +1520,6 @@ static void __exit dma_buf_deinit(void)
 {
        dma_buf_uninit_debugfs();
        kern_unmount(dma_buf_mnt);
+       dma_buf_uninit_sysfs_statistics();
 }
 __exitcall(dma_buf_deinit);