dma-buf: add DMA_BUF_SET_NAME ioctls
This patch adds complimentary DMA_BUF_SET_NAME ioctls, which lets userspace processes attach a free-form name to each buffer. This information can be extremely helpful for tracking and accounting shared buffers. For example, on Android, we know what each buffer will be used for at allocation time: GL, multimedia, camera, etc. The userspace allocator can use DMA_BUF_SET_NAME to associate that information with the buffer, so we can later give developers a breakdown of how much memory they're allocating for graphics, camera, etc. Signed-off-by: Greg Hackmann <ghackmann@google.com> Signed-off-by: Chenbo Feng <fengc@google.com> Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org> Link: https://patchwork.freedesktop.org/patch/msgid/20190613223408.139221-3-fengc@google.com
This commit is contained in:
parent
ed63bb1d1f
commit
bb2bb90304
|
@ -48,8 +48,24 @@ struct dma_buf_list {
|
||||||
|
|
||||||
static struct dma_buf_list db_list;
|
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;
|
||||||
|
mutex_lock(&dmabuf->lock);
|
||||||
|
if (dmabuf->name)
|
||||||
|
ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN);
|
||||||
|
mutex_unlock(&dmabuf->lock);
|
||||||
|
|
||||||
|
return dynamic_dname(dentry, buffer, buflen, "/%s:%s",
|
||||||
|
dentry->d_name.name, ret > 0 ? name : "");
|
||||||
|
}
|
||||||
|
|
||||||
static const struct dentry_operations dma_buf_dentry_ops = {
|
static const struct dentry_operations dma_buf_dentry_ops = {
|
||||||
.d_dname = simple_dname,
|
.d_dname = dmabuffs_dname,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct vfsmount *dma_buf_mnt;
|
static struct vfsmount *dma_buf_mnt;
|
||||||
|
@ -301,6 +317,43 @@ out:
|
||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dma_buf_set_name - Set a name to a specific dma_buf to track the usage.
|
||||||
|
* The name of the dma-buf buffer can only be set when the dma-buf is not
|
||||||
|
* attached to any devices. It could theoritically support changing the
|
||||||
|
* name of the dma-buf if the same piece of memory is used for multiple
|
||||||
|
* purpose between different devices.
|
||||||
|
*
|
||||||
|
* @dmabuf [in] dmabuf buffer that will be renamed.
|
||||||
|
* @buf: [in] A piece of userspace memory that contains the name of
|
||||||
|
* the dma-buf.
|
||||||
|
*
|
||||||
|
* Returns 0 on success. If the dma-buf buffer is already attached to
|
||||||
|
* devices, return -EBUSY.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf)
|
||||||
|
{
|
||||||
|
char *name = strndup_user(buf, DMA_BUF_NAME_LEN);
|
||||||
|
long ret = 0;
|
||||||
|
|
||||||
|
if (IS_ERR(name))
|
||||||
|
return PTR_ERR(name);
|
||||||
|
|
||||||
|
mutex_lock(&dmabuf->lock);
|
||||||
|
if (!list_empty(&dmabuf->attachments)) {
|
||||||
|
ret = -EBUSY;
|
||||||
|
kfree(name);
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
kfree(dmabuf->name);
|
||||||
|
dmabuf->name = name;
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
mutex_unlock(&dmabuf->lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static long dma_buf_ioctl(struct file *file,
|
static long dma_buf_ioctl(struct file *file,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
|
@ -339,6 +392,10 @@ static long dma_buf_ioctl(struct file *file,
|
||||||
ret = dma_buf_begin_cpu_access(dmabuf, direction);
|
ret = dma_buf_begin_cpu_access(dmabuf, direction);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
case DMA_BUF_SET_NAME:
|
||||||
|
return dma_buf_set_name(dmabuf, (const char __user *)arg);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
@ -380,6 +437,7 @@ static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags)
|
||||||
goto err_alloc_file;
|
goto err_alloc_file;
|
||||||
file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
|
file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
|
||||||
file->private_data = dmabuf;
|
file->private_data = dmabuf;
|
||||||
|
file->f_path.dentry->d_fsdata = dmabuf;
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
|
|
||||||
|
@ -1112,12 +1170,13 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\t%08lu\n",
|
seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\t%08lu\t%s\n",
|
||||||
buf_obj->size,
|
buf_obj->size,
|
||||||
buf_obj->file->f_flags, buf_obj->file->f_mode,
|
buf_obj->file->f_flags, buf_obj->file->f_mode,
|
||||||
file_count(buf_obj->file),
|
file_count(buf_obj->file),
|
||||||
buf_obj->exp_name,
|
buf_obj->exp_name,
|
||||||
file_inode(buf_obj->file)->i_ino);
|
file_inode(buf_obj->file)->i_ino,
|
||||||
|
buf_obj->name ?: "");
|
||||||
|
|
||||||
robj = buf_obj->resv;
|
robj = buf_obj->resv;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
@ -280,10 +280,12 @@ struct dma_buf_ops {
|
||||||
* @file: file pointer used for sharing buffers across, and for refcounting.
|
* @file: file pointer used for sharing buffers across, and for refcounting.
|
||||||
* @attachments: list of dma_buf_attachment that denotes all devices attached.
|
* @attachments: list of dma_buf_attachment that denotes all devices attached.
|
||||||
* @ops: dma_buf_ops associated with this buffer object.
|
* @ops: dma_buf_ops associated with this buffer object.
|
||||||
* @lock: used internally to serialize list manipulation, attach/detach and vmap/unmap
|
* @lock: used internally to serialize list manipulation, attach/detach and
|
||||||
|
* vmap/unmap, and accesses to name
|
||||||
* @vmapping_counter: used internally to refcnt the vmaps
|
* @vmapping_counter: used internally to refcnt the vmaps
|
||||||
* @vmap_ptr: the current vmap ptr if vmapping_counter > 0
|
* @vmap_ptr: the current vmap ptr if vmapping_counter > 0
|
||||||
* @exp_name: name of the exporter; useful for debugging.
|
* @exp_name: name of the exporter; useful for debugging.
|
||||||
|
* @name: userspace-provided name; useful for accounting and debugging.
|
||||||
* @owner: pointer to exporter module; used for refcounting when exporter is a
|
* @owner: pointer to exporter module; used for refcounting when exporter is a
|
||||||
* kernel module.
|
* kernel module.
|
||||||
* @list_node: node for dma_buf accounting and debugging.
|
* @list_node: node for dma_buf accounting and debugging.
|
||||||
|
@ -311,6 +313,7 @@ struct dma_buf {
|
||||||
unsigned vmapping_counter;
|
unsigned vmapping_counter;
|
||||||
void *vmap_ptr;
|
void *vmap_ptr;
|
||||||
const char *exp_name;
|
const char *exp_name;
|
||||||
|
const char *name;
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
struct list_head list_node;
|
struct list_head list_node;
|
||||||
void *priv;
|
void *priv;
|
||||||
|
|
|
@ -35,7 +35,10 @@ struct dma_buf_sync {
|
||||||
#define DMA_BUF_SYNC_VALID_FLAGS_MASK \
|
#define DMA_BUF_SYNC_VALID_FLAGS_MASK \
|
||||||
(DMA_BUF_SYNC_RW | DMA_BUF_SYNC_END)
|
(DMA_BUF_SYNC_RW | DMA_BUF_SYNC_END)
|
||||||
|
|
||||||
|
#define DMA_BUF_NAME_LEN 32
|
||||||
|
|
||||||
#define DMA_BUF_BASE 'b'
|
#define DMA_BUF_BASE 'b'
|
||||||
#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
|
#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
|
||||||
|
#define DMA_BUF_SET_NAME _IOW(DMA_BUF_BASE, 1, const char *)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue