// SPDX-License-Identifier: GPL-2.0-only
/*
* Framework for buffer objects that can be shared across devices/subsystems.
*
* Copyright(C) 2011 Linaro Limited. All rights reserved.
* Author: Sumit Semwal <sumit.semwal@ti.com>
*
* Many thanks to linaro-mm-sig list, and specially
* Arnd Bergmann <arnd@arndb.de>, Rob Clark <rob@ti.com> and
* Daniel Vetter <daniel@ffwll.ch> for their support in creation and
* refining of this idea.
*/
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/dma-buf.h>
#include <linux/dma-fence.h>
#include <linux/anon_inodes.h>
#include <linux/export.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/sync_file.h>
#include <linux/poll.h>
#include <linux/dma-resv.h>
#include <linux/mm.h>
#include <linux/mount.h>
#include <linux/pseudo_fs.h>
#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 {
struct list_head head;
struct mutex lock;
};
static struct dma_buf_list db_list;
static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen)
{
struct dma_buf *dmabuf;
char name[DMA_BUF_NAME_LEN];
size_t ret = 0;
dmabuf = dentry->d_fsdata;
spin_lock(&dmabuf->name_lock);
if (dmabuf->name)
ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN);
spin_unlock(&dmabuf->name_lock);
return dynamic_dname(dentry, buffer, buflen, "/%s:%s",
dentry->d_name.name, ret > 0 ? name : "");
}
static void dma_buf_release(struct dentry *dentry)
{
struct dma_buf *dmabuf;
dmabuf = dentry->d_fsdata;
if (unlikely(!dmabuf))
return;
BUG_ON(dmabuf->vmapping_counter);
/*
* If you hit this BUG() it could mean:
* * There's a file reference imbalance in dma_buf_poll / dma_buf_poll_cb or somewhere else
* * dmabuf->cb_in/out.active are non-0 despite no pending fence callback
*/
BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
dma_buf_stats_teardown(dmabuf);
dmabuf->ops->release(dmabuf);
if (dmabuf->resv == (struct dma_resv *)&dmabuf[1])
dma_resv_fini(dmabuf->resv);
WARN_ON(!list_empty(&dmabuf->attachments));
module_put(dmabuf->owner);
kfree(dmabuf->name);
kfree(dmabuf);
}
static int dma_buf_file_release(struct inode *inode, struct file *file)
{
struct dma_buf *dmabuf;
if (!is_dma_buf_file(file))
return -EINVAL;
dmabuf = file->private_data;
mutex_lock(&db_list.lock);
list_del(&dmabuf->list_node);
mutex_unlock(&db_list.lock);
return 0;
}
static const struct dentry_operations dma_buf_dentry_ops = {
.d_dname = dmabuffs_dname,
.d_release = dma_buf_release,
};
static struct vfsmount *dma_buf_mnt;
static int dma_buf_fs_init_context(struct fs_context *fc)
{
struct pseudo_fs_context *ctx;
ctx = init_pseudo(fc, DMA_BUF_MAGIC);
if (!ctx)
return -ENOMEM;
ctx->dops = &dma_buf_dentry_ops;
return 0;
}
static struct file_system_type dma_buf_fs_type = {
.name = "dmabuf",
.init_fs_context = dma_buf_fs_init_context,
.kill_sb = kill_anon_super,
};
static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
{
struct dma_buf *dmabuf;
if (!is_dma_buf_file(file))
return -EINVAL;
dmabuf = file->private_data;
/* check if buffer supports mmap */
if (!dmabuf->ops->mmap)
return -EINVAL;
/* check for overflowing the buffer's size */
if (vma->vm_pgoff + vma_pages(vma) >
dmabuf->size >> PAGE_SHIFT)
return -EINVAL;
return dmabuf->ops->mmap(dmabuf, vma);
}
static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
{
struct dma_buf *dmabuf;
loff_t base;
if (!is_dma_buf_file(file))
return -EBADF;
dmabuf = file->private_data;
/* only support discovering the end of the buffer,
but also allow SEEK_SET to maintain the idiomatic
SEEK_END(0), SEEK_CUR(0) pattern */
if (whence == SEEK_END)
base = dmabuf->size;
else if (whence == SEEK_SET)
base = 0;
else
return -EINVAL;
if (offset != 0)
return -EINVAL;
return base + offset;
}
/**
* DOC: implicit fence polling
*
* To support cross-device and cross-driver synchronization of buffer access
* implicit fences (represented internally in the kernel with &struct dma_fence)
* can be attached to a &dma_buf. The glue for that and a few related things are
* provided in the &dma_resv structure.
*
* Userspace can query the state of these implicitly tracked fences using poll()
* and related system calls:
*
* - Checking for EPOLLIN, i.e. read access, can be use to query the state of the
* most recent write or exclusive fence.
*
* - Checking for EPOLLOUT, i.e. write access, can be used to query the state of
* all attached fences, shared and exclusive ones.
*
* Note that this only signals the completion of the respective fences, i.e. the
* DMA transfers are complete. Cache flushing and any other necessary
* preparations before CPU access can begin still need to happen.
*
* As an alternative to poll(), the set of fences on DMA buffer can be
* exported as a &sync_file using &dma_buf_sync_file_export.
*/
static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
{
struct dma_buf_poll_cb_t *dcb = (struct dma_buf_poll_cb_t *)cb;
struct dma_buf *dmabuf = container_of(dcb->poll, struct dma_buf, poll);
unsigned long flags;
spin_lock_irqsave(&dcb->poll->lock, flags);
wake_up_locked_poll(dcb->poll, dcb->active);
dcb->active
|