Skip to content

Commit ed63bb1

Browse files
greghackmannsumitsemwal
authored andcommitted
dma-buf: give each buffer a full-fledged inode
By traversing /proc/*/fd and /proc/*/map_files, processes with CAP_ADMIN can get a lot of fine-grained data about how shmem buffers are shared among processes. stat(2) on each entry gives the caller a unique ID (st_ino), the buffer's size (st_size), and even the number of pages currently charged to the buffer (st_blocks / 512). In contrast, all dma-bufs share the same anonymous inode. So while we can count how many dma-buf fds or mappings a process has, we can't get the size of the backing buffers or tell if two entries point to the same dma-buf. On systems with debugfs, we can get a per-buffer breakdown of size and reference count, but can't tell which processes are actually holding the references to each buffer. Replace the singleton inode with full-fledged inodes allocated by alloc_anon_inode(). This involves creating and mounting a mini-pseudo-filesystem for dma-buf, following the example in fs/aio.c. Signed-off-by: Greg Hackmann <[email protected]> Signed-off-by: Chenbo Feng <[email protected]> Signed-off-by: Sumit Semwal <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 51e857a commit ed63bb1

File tree

2 files changed

+58
-6
lines changed

2 files changed

+58
-6
lines changed

drivers/dma-buf/dma-buf.c

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@
3434
#include <linux/poll.h>
3535
#include <linux/reservation.h>
3636
#include <linux/mm.h>
37+
#include <linux/mount.h>
3738

3839
#include <uapi/linux/dma-buf.h>
40+
#include <uapi/linux/magic.h>
3941

4042
static inline int is_dma_buf_file(struct file *);
4143

@@ -46,6 +48,25 @@ struct dma_buf_list {
4648

4749
static struct dma_buf_list db_list;
4850

51+
static const struct dentry_operations dma_buf_dentry_ops = {
52+
.d_dname = simple_dname,
53+
};
54+
55+
static struct vfsmount *dma_buf_mnt;
56+
57+
static struct dentry *dma_buf_fs_mount(struct file_system_type *fs_type,
58+
int flags, const char *name, void *data)
59+
{
60+
return mount_pseudo(fs_type, "dmabuf:", NULL, &dma_buf_dentry_ops,
61+
DMA_BUF_MAGIC);
62+
}
63+
64+
static struct file_system_type dma_buf_fs_type = {
65+
.name = "dmabuf",
66+
.mount = dma_buf_fs_mount,
67+
.kill_sb = kill_anon_super,
68+
};
69+
4970
static int dma_buf_release(struct inode *inode, struct file *file)
5071
{
5172
struct dma_buf *dmabuf;
@@ -342,6 +363,31 @@ static inline int is_dma_buf_file(struct file *file)
342363
return file->f_op == &dma_buf_fops;
343364
}
344365

366+
static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags)
367+
{
368+
struct file *file;
369+
struct inode *inode = alloc_anon_inode(dma_buf_mnt->mnt_sb);
370+
371+
if (IS_ERR(inode))
372+
return ERR_CAST(inode);
373+
374+
inode->i_size = dmabuf->size;
375+
inode_set_bytes(inode, dmabuf->size);
376+
377+
file = alloc_file_pseudo(inode, dma_buf_mnt, "dmabuf",
378+
flags, &dma_buf_fops);
379+
if (IS_ERR(file))
380+
goto err_alloc_file;
381+
file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
382+
file->private_data = dmabuf;
383+
384+
return file;
385+
386+
err_alloc_file:
387+
iput(inode);
388+
return file;
389+
}
390+
345391
/**
346392
* DOC: dma buf device access
347393
*
@@ -436,8 +482,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
436482
}
437483
dmabuf->resv = resv;
438484

439-
file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf,
440-
exp_info->flags);
485+
file = dma_buf_getfile(dmabuf, exp_info->flags);
441486
if (IS_ERR(file)) {
442487
ret = PTR_ERR(file);
443488
goto err_dmabuf;
@@ -1055,8 +1100,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
10551100
return ret;
10561101

10571102
seq_puts(s, "\nDma-buf Objects:\n");
1058-
seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\n",
1059-
"size", "flags", "mode", "count");
1103+
seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\n",
1104+
"size", "flags", "mode", "count", "ino");
10601105

10611106
list_for_each_entry(buf_obj, &db_list.head, list_node) {
10621107
ret = mutex_lock_interruptible(&buf_obj->lock);
@@ -1067,11 +1112,12 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
10671112
continue;
10681113
}
10691114

1070-
seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\n",
1115+
seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\t%08lu\n",
10711116
buf_obj->size,
10721117
buf_obj->file->f_flags, buf_obj->file->f_mode,
10731118
file_count(buf_obj->file),
1074-
buf_obj->exp_name);
1119+
buf_obj->exp_name,
1120+
file_inode(buf_obj->file)->i_ino);
10751121

10761122
robj = buf_obj->resv;
10771123
while (true) {
@@ -1167,6 +1213,10 @@ static inline void dma_buf_uninit_debugfs(void)
11671213

11681214
static int __init dma_buf_init(void)
11691215
{
1216+
dma_buf_mnt = kern_mount(&dma_buf_fs_type);
1217+
if (IS_ERR(dma_buf_mnt))
1218+
return PTR_ERR(dma_buf_mnt);
1219+
11701220
mutex_init(&db_list.lock);
11711221
INIT_LIST_HEAD(&db_list.head);
11721222
dma_buf_init_debugfs();
@@ -1177,5 +1227,6 @@ subsys_initcall(dma_buf_init);
11771227
static void __exit dma_buf_deinit(void)
11781228
{
11791229
dma_buf_uninit_debugfs();
1230+
kern_unmount(dma_buf_mnt);
11801231
}
11811232
__exitcall(dma_buf_deinit);

include/uapi/linux/magic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,6 @@
9191
#define UDF_SUPER_MAGIC 0x15013346
9292
#define BALLOON_KVM_MAGIC 0x13661366
9393
#define ZSMALLOC_MAGIC 0x58295829
94+
#define DMA_BUF_MAGIC 0x444d4142 /* "DMAB" */
9495

9596
#endif /* __LINUX_MAGIC_H__ */

0 commit comments

Comments
 (0)