Skip to content

Replace CONFIG_DMABUF_SYSFS_STATS with BPF #8942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 78 additions & 20 deletions drivers/dma-buf/dma-buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
#include <linux/anon_inodes.h>
#include <linux/export.h>
#include <linux/debugfs.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/seq_file.h>
#include <linux/sync_file.h>
#include <linux/poll.h>
Expand All @@ -35,35 +37,91 @@

static inline int is_dma_buf_file(struct file *);

#if IS_ENABLED(CONFIG_DEBUG_FS)
static DEFINE_MUTEX(debugfs_list_mutex);
static LIST_HEAD(debugfs_list);
static DEFINE_MUTEX(dmabuf_list_mutex);
static LIST_HEAD(dmabuf_list);

static void __dma_buf_debugfs_list_add(struct dma_buf *dmabuf)
static void __dma_buf_list_add(struct dma_buf *dmabuf)
{
mutex_lock(&debugfs_list_mutex);
list_add(&dmabuf->list_node, &debugfs_list);
mutex_unlock(&debugfs_list_mutex);
mutex_lock(&dmabuf_list_mutex);
list_add(&dmabuf->list_node, &dmabuf_list);
mutex_unlock(&dmabuf_list_mutex);
}

static void __dma_buf_debugfs_list_del(struct dma_buf *dmabuf)
static void __dma_buf_list_del(struct dma_buf *dmabuf)
{
if (!dmabuf)
return;

mutex_lock(&debugfs_list_mutex);
mutex_lock(&dmabuf_list_mutex);
list_del(&dmabuf->list_node);
mutex_unlock(&debugfs_list_mutex);
mutex_unlock(&dmabuf_list_mutex);
}
#else
static void __dma_buf_debugfs_list_add(struct dma_buf *dmabuf)

/**
* dma_buf_iter_begin - begin iteration through global list of all DMA buffers
*
* Returns the first buffer in the global list of DMA-bufs that's not in the
* process of being destroyed. Increments that buffer's reference count to
* prevent buffer destruction. Callers must release the reference, either by
* continuing iteration with dma_buf_iter_next(), or with dma_buf_put().
*
* Return:
* * First buffer from global list, with refcount elevated
* * NULL if no active buffers are present
*/
struct dma_buf *dma_buf_iter_begin(void)
{
struct dma_buf *ret = NULL, *dmabuf;

/*
* The list mutex does not protect a dmabuf's refcount, so it can be
* zeroed while we are iterating. We cannot call get_dma_buf() since the
* caller may not already own a reference to the buffer.
*/
mutex_lock(&dmabuf_list_mutex);
list_for_each_entry(dmabuf, &dmabuf_list, list_node) {
if (file_ref_get(&dmabuf->file->f_ref)) {
ret = dmabuf;
break;
}
}
mutex_unlock(&dmabuf_list_mutex);
return ret;
}

static void __dma_buf_debugfs_list_del(struct dma_buf *dmabuf)
/**
* dma_buf_iter_next - continue iteration through global list of all DMA buffers
* @dmabuf: [in] pointer to dma_buf
*
* Decrements the reference count on the provided buffer. Returns the next
* buffer from the remainder of the global list of DMA-bufs with its reference
* count incremented. Callers must release the reference, either by continuing
* iteration with dma_buf_iter_next(), or with dma_buf_put().
*
* Return:
* * Next buffer from global list, with refcount elevated
* * NULL if no additional active buffers are present
*/
struct dma_buf *dma_buf_iter_next(struct dma_buf *dmabuf)
{
struct dma_buf *ret = NULL;

/*
* The list mutex does not protect a dmabuf's refcount, so it can be
* zeroed while we are iterating. We cannot call get_dma_buf() since the
* caller may not already own a reference to the buffer.
*/
mutex_lock(&dmabuf_list_mutex);
dma_buf_put(dmabuf);
list_for_each_entry_continue(dmabuf, &dmabuf_list, list_node) {
if (file_ref_get(&dmabuf->file->f_ref)) {
ret = dmabuf;
break;
}
}
mutex_unlock(&dmabuf_list_mutex);
return ret;
}
#endif

static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen)
{
Expand Down Expand Up @@ -115,7 +173,7 @@ static int dma_buf_file_release(struct inode *inode, struct file *file)
if (!is_dma_buf_file(file))
return -EINVAL;

__dma_buf_debugfs_list_del(file->private_data);
__dma_buf_list_del(file->private_data);

return 0;
}
Expand Down Expand Up @@ -689,7 +747,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
file->f_path.dentry->d_fsdata = dmabuf;
dmabuf->file = file;

__dma_buf_debugfs_list_add(dmabuf);
__dma_buf_list_add(dmabuf);

return dmabuf;

Expand Down Expand Up @@ -1630,7 +1688,7 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
size_t size = 0;
int ret;

ret = mutex_lock_interruptible(&debugfs_list_mutex);
ret = mutex_lock_interruptible(&dmabuf_list_mutex);

if (ret)
return ret;
Expand All @@ -1639,7 +1697,7 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\tname\n",
"size", "flags", "mode", "count", "ino");

list_for_each_entry(buf_obj, &debugfs_list, list_node) {
list_for_each_entry(buf_obj, &dmabuf_list, list_node) {

ret = dma_resv_lock_interruptible(buf_obj->resv, NULL);
if (ret)
Expand Down Expand Up @@ -1676,11 +1734,11 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)

seq_printf(s, "\nTotal %d objects, %zu bytes\n", count, size);

mutex_unlock(&debugfs_list_mutex);
mutex_unlock(&dmabuf_list_mutex);
return 0;

error_unlock:
mutex_unlock(&debugfs_list_mutex);
mutex_unlock(&dmabuf_list_mutex);
return ret;
}

Expand Down
4 changes: 2 additions & 2 deletions include/linux/dma-buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -370,10 +370,8 @@ struct dma_buf {
*/
struct module *owner;

#if IS_ENABLED(CONFIG_DEBUG_FS)
/** @list_node: node for dma_buf accounting and debugging. */
struct list_head list_node;
#endif

/** @priv: exporter specific private data for this buffer object. */
void *priv;
Expand Down Expand Up @@ -636,4 +634,6 @@ int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map);
void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map);
int dma_buf_vmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map);
void dma_buf_vunmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map);
struct dma_buf *dma_buf_iter_begin(void);
struct dma_buf *dma_buf_iter_next(struct dma_buf *dmbuf);
#endif /* __DMA_BUF_H__ */
3 changes: 3 additions & 0 deletions kernel/bpf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ obj-$(CONFIG_BPF_SYSCALL) += relo_core.o
obj-$(CONFIG_BPF_SYSCALL) += btf_iter.o
obj-$(CONFIG_BPF_SYSCALL) += btf_relocate.o
obj-$(CONFIG_BPF_SYSCALL) += kmem_cache_iter.o
ifeq ($(CONFIG_DMA_SHARED_BUFFER),y)
obj-$(CONFIG_BPF_SYSCALL) += dmabuf_iter.o
endif

CFLAGS_REMOVE_percpu_freelist.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_bpf_lru_list.o = $(CC_FLAGS_FTRACE)
Expand Down
150 changes: 150 additions & 0 deletions kernel/bpf/dmabuf_iter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2025 Google LLC */
#include <linux/bpf.h>
#include <linux/btf_ids.h>
#include <linux/dma-buf.h>
#include <linux/kernel.h>
#include <linux/seq_file.h>

static void *dmabuf_iter_seq_start(struct seq_file *seq, loff_t *pos)
{
if (*pos)
return NULL;

return dma_buf_iter_begin();
}

static void *dmabuf_iter_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct dma_buf *dmabuf = v;

++*pos;

return dma_buf_iter_next(dmabuf);
}

struct bpf_iter__dmabuf {
__bpf_md_ptr(struct bpf_iter_meta *, meta);
__bpf_md_ptr(struct dma_buf *, dmabuf);
};

static int __dmabuf_seq_show(struct seq_file *seq, void *v, bool in_stop)
{
struct bpf_iter_meta meta = {
.seq = seq,
};
struct bpf_iter__dmabuf ctx = {
.meta = &meta,
.dmabuf = v,
};
struct bpf_prog *prog = bpf_iter_get_info(&meta, in_stop);

if (prog)
return bpf_iter_run_prog(prog, &ctx);

return 0;
}

static int dmabuf_iter_seq_show(struct seq_file *seq, void *v)
{
return __dmabuf_seq_show(seq, v, false);
}

static void dmabuf_iter_seq_stop(struct seq_file *seq, void *v)
{
struct dma_buf *dmabuf = v;

if (dmabuf)
dma_buf_put(dmabuf);
}

static const struct seq_operations dmabuf_iter_seq_ops = {
.start = dmabuf_iter_seq_start,
.next = dmabuf_iter_seq_next,
.stop = dmabuf_iter_seq_stop,
.show = dmabuf_iter_seq_show,
};

static void bpf_iter_dmabuf_show_fdinfo(const struct bpf_iter_aux_info *aux,
struct seq_file *seq)
{
seq_puts(seq, "dmabuf iter\n");
}

static const struct bpf_iter_seq_info dmabuf_iter_seq_info = {
.seq_ops = &dmabuf_iter_seq_ops,
.init_seq_private = NULL,
.fini_seq_private = NULL,
.seq_priv_size = 0,
};

static struct bpf_iter_reg bpf_dmabuf_reg_info = {
.target = "dmabuf",
.feature = BPF_ITER_RESCHED,
.show_fdinfo = bpf_iter_dmabuf_show_fdinfo,
.ctx_arg_info_size = 1,
.ctx_arg_info = {
{ offsetof(struct bpf_iter__dmabuf, dmabuf),
PTR_TO_BTF_ID_OR_NULL },
},
.seq_info = &dmabuf_iter_seq_info,
};

DEFINE_BPF_ITER_FUNC(dmabuf, struct bpf_iter_meta *meta, struct dma_buf *dmabuf)
BTF_ID_LIST_SINGLE(bpf_dmabuf_btf_id, struct, dma_buf)

static int __init dmabuf_iter_init(void)
{
bpf_dmabuf_reg_info.ctx_arg_info[0].btf_id = bpf_dmabuf_btf_id[0];
return bpf_iter_reg_target(&bpf_dmabuf_reg_info);
}

late_initcall(dmabuf_iter_init);

struct bpf_iter_dmabuf {
/*
* opaque iterator state; having __u64 here allows to preserve correct
* alignment requirements in vmlinux.h, generated from BTF
*/
__u64 __opaque[1];
} __aligned(8);

/* Non-opaque version of bpf_iter_dmabuf */
struct bpf_iter_dmabuf_kern {
struct dma_buf *dmabuf;
} __aligned(8);

__bpf_kfunc_start_defs();

__bpf_kfunc int bpf_iter_dmabuf_new(struct bpf_iter_dmabuf *it)
{
struct bpf_iter_dmabuf_kern *kit = (void *)it;

BUILD_BUG_ON(sizeof(*kit) > sizeof(*it));
BUILD_BUG_ON(__alignof__(*kit) != __alignof__(*it));

kit->dmabuf = NULL;
return 0;
}

__bpf_kfunc struct dma_buf *bpf_iter_dmabuf_next(struct bpf_iter_dmabuf *it)
{
struct bpf_iter_dmabuf_kern *kit = (void *)it;

if (kit->dmabuf)
kit->dmabuf = dma_buf_iter_next(kit->dmabuf);
else
kit->dmabuf = dma_buf_iter_begin();

return kit->dmabuf;
}

__bpf_kfunc void bpf_iter_dmabuf_destroy(struct bpf_iter_dmabuf *it)
{
struct bpf_iter_dmabuf_kern *kit = (void *)it;

if (kit->dmabuf)
dma_buf_put(kit->dmabuf);
}

__bpf_kfunc_end_defs();
5 changes: 5 additions & 0 deletions kernel/bpf/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -3294,6 +3294,11 @@ BTF_ID_FLAGS(func, bpf_iter_kmem_cache_next, KF_ITER_NEXT | KF_RET_NULL | KF_SLE
BTF_ID_FLAGS(func, bpf_iter_kmem_cache_destroy, KF_ITER_DESTROY | KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_local_irq_save)
BTF_ID_FLAGS(func, bpf_local_irq_restore)
#ifdef CONFIG_DMA_SHARED_BUFFER
BTF_ID_FLAGS(func, bpf_iter_dmabuf_new, KF_ITER_NEW | KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_iter_dmabuf_next, KF_ITER_NEXT | KF_RET_NULL | KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_iter_dmabuf_destroy, KF_ITER_DESTROY | KF_SLEEPABLE)
#endif
BTF_KFUNCS_END(common_btf_ids)

static const struct btf_kfunc_id_set common_kfunc_set = {
Expand Down
5 changes: 5 additions & 0 deletions tools/testing/selftests/bpf/bpf_experimental.h
Original file line number Diff line number Diff line change
Expand Up @@ -591,4 +591,9 @@ extern int bpf_iter_kmem_cache_new(struct bpf_iter_kmem_cache *it) __weak __ksym
extern struct kmem_cache *bpf_iter_kmem_cache_next(struct bpf_iter_kmem_cache *it) __weak __ksym;
extern void bpf_iter_kmem_cache_destroy(struct bpf_iter_kmem_cache *it) __weak __ksym;

struct bpf_iter_dmabuf;
extern int bpf_iter_dmabuf_new(struct bpf_iter_dmabuf *it) __weak __ksym;
extern struct dma_buf *bpf_iter_dmabuf_next(struct bpf_iter_dmabuf *it) __weak __ksym;
extern void bpf_iter_dmabuf_destroy(struct bpf_iter_dmabuf *it) __weak __ksym;

#endif
3 changes: 3 additions & 0 deletions tools/testing/selftests/bpf/config
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ CONFIG_CRYPTO_AES=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_BTF=y
CONFIG_DEBUG_INFO_DWARF4=y
CONFIG_DMABUF_HEAPS=y
CONFIG_DMABUF_HEAPS_SYSTEM=y
CONFIG_DUMMY=y
CONFIG_DYNAMIC_FTRACE=y
CONFIG_FPROBE=y
Expand Down Expand Up @@ -108,6 +110,7 @@ CONFIG_SECURITY=y
CONFIG_SECURITYFS=y
CONFIG_SYN_COOKIES=y
CONFIG_TEST_BPF=m
CONFIG_UDMABUF=y
CONFIG_USERFAULTFD=y
CONFIG_VSOCKETS=y
CONFIG_VXLAN=y
Expand Down
Loading
Loading