1. 背景與意義
1.1 異構系統與緩沖區共享的挑戰
在現代 SoC、嵌入式、圖形和多媒體系統中,CPU、GPU、VPU、ISP、DMA 控制器等多個硬件單元需要高效地共享和傳遞大塊數據(如圖像幀、視頻流、AI 張量等)。如果每個設備都維護獨立的緩沖區,數據在設備間傳遞時就需要頻繁拷貝,極大浪費帶寬和內存,降低系統性能。
1.2 dma-buf 的目標
dma-buf?框架是 Linux 內核為解決“跨設備零拷貝緩沖區共享”而設計的通用機制。其核心目標包括:
-
跨驅動、跨設備共享物理緩沖區,避免冗余拷貝。
-
標準化緩沖區導出、導入、映射、同步等操作,簡化驅動開發。
-
支持多種內存類型(系統內存、顯存、專用區域等),適應復雜硬件架構。
-
支持同步機制(fence),保證多設備并發訪問的數據一致性。
2. dma-buf 的核心原理
2.1 角色劃分
-
Exporter(導出者):負責分配和管理物理緩沖區的驅動(如 GPU、VPU、分配器等)。
-
Importer(導入者):需要訪問該緩沖區的其他驅動(如顯示控制器、ISP、DMA 控制器等)。
-
dma-buf 核心框架:為 exporter 和 importer 提供標準化的緩沖區共享、映射、同步等接口。
2.2 共享機制
-
Exporter 通過?
dma_buf_export()
?導出一個物理緩沖區,獲得一個?struct dma_buf
?對象,并為其分配一個匿名文件描述符(fd)。 -
Importer 通過 fd 調用?
dma_buf_get()
?或?dma_buf_attach()
,獲得對該緩沖區的訪問權。 -
Importer 可通過?
dma_buf_map_attachment()
?將緩沖區映射到自己的設備地址空間,實現零拷貝訪問。 -
多個 importer 可同時 attach 同一個 dma-buf,實現多設備并發訪問。
dma-buf機制建立在?anon_inode之上,是 anon_inode技術一個重要應用示例。
2.3 同步機制
-
dma-buf 支持 fence(同步柵欄)機制,保證多設備并發訪問時的數據一致性。
-
Exporter/Importer 可通過?
dma_resv
?對象管理讀寫 fence,協調訪問時序。
3. 關鍵數據結構與實現
3.1 struct dma_buf_ops
dma_buf_ops
?定義了 dma-buf 的所有操作接口,由 exporter 實現。
struct dma_buf_ops {int (*attach)(struct dma_buf *, struct dma_buf_attachment *);void (*detach)(struct dma_buf *, struct dma_buf_attachment *);int (*pin)(struct dma_buf_attachment *attach);void (*unpin)(struct dma_buf_attachment *attach);struct sg_table *(*map_dma_buf)(struct dma_buf_attachment *, enum dma_data_direction);void (*unmap_dma_buf)(struct dma_buf_attachment *, struct sg_table *, enum dma_data_direction);void (*release)(struct dma_buf *);int (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction);int (*end_cpu_access)(struct dma_buf *, enum dma_data_direction);int (*mmap)(struct dma_buf *, struct vm_area_struct *vma);int (*vmap)(struct dma_buf *dmabuf, struct iosys_map *map);void (*vunmap)(struct dma_buf *dmabuf, struct iosys_map *map);
};
-
attach/detach:設備 attach/detach 緩沖區時的回調。
-
pin/unpin:鎖定/解鎖緩沖區,防止被移動。
-
map/unmap_dma_buf:將緩沖區映射到設備地址空間。
-
release:最后一個引用釋放時的清理回調。
-
begin/end_cpu_access:CPU 訪問前后的同步操作(如 cache flush)。
-
mmap/vmap/vunmap:內核/用戶空間映射支持。
3.2 struct dma_buf
dma_buf
?是 dma-buf 的核心對象,描述一個可共享的物理緩沖區。
struct dma_buf {size_t size;struct file *file;struct list_head attachments;const struct dma_buf_ops *ops;unsigned vmapping_counter;struct iosys_map vmap_ptr;const char *exp_name;const char *name;spinlock_t name_lock;struct module *owner;struct list_head list_node;void *priv;struct dma_resv *resv;wait_queue_head_t poll;struct dma_buf_poll_cb_t cb_in, cb_out;// ... 其他成員
};
-
size:緩沖區大小。
-
file:匿名文件,用于 fd 傳遞和引用計數。
-
attachments:所有 attach 到該緩沖區的設備鏈表。
-
ops:操作函數集。
-
resv:同步對象,管理 fence。
-
poll/cb_in/cb_out:支持用戶空間 poll/epoll 事件通知。
3.3 struct dma_buf_attachment
描述一個設備與 dma-buf 的關聯關系。
struct dma_buf_attachment {struct dma_buf *dmabuf;struct device *dev;struct list_head node;bool peer2peer;const struct dma_buf_attach_ops *importer_ops;void *importer_priv;void *priv;
};
-
dmabuf:關聯的 dma-buf。
-
dev:關聯的設備。
-
priv:exporter/importer 的私有數據。
3.4 struct dma_buf_export_info
導出 dma-buf 時的參數描述。
struct dma_buf_export_info {const char *exp_name;struct module *owner;const struct dma_buf_ops *ops;size_t size;int flags;struct dma_resv *resv;void *priv;
};
4. 主要 API 及用法
4.1 Exporter 側
4.1.1 導出緩沖區
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
exp_info.ops = &my_dma_buf_ops;
exp_info.size = buffer_size;
exp_info.priv = my_priv_data;
struct dma_buf *dmabuf = dma_buf_export(&exp_info);
4.1.2 獲取 fd
int fd = dma_buf_fd(dmabuf, O_CLOEXEC);
4.1.3 釋放緩沖區
dma_buf_put(dmabuf);
4.2 Importer 側
4.2.1 通過 fd 獲取 dma-buf
struct dma_buf *dmabuf = dma_buf_get(fd);
4.2.2 設備 attach
struct dma_buf_attachment *attach = dma_buf_attach(dmabuf, dev);
4.2.3 映射到設備地址空間
struct sg_table *sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
4.2.4 解除映射與 detach
dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
dma_buf_detach(dmabuf, attach);
4.2.5 釋放 dma-buf
dma_buf_put(dmabuf);
4.3 CPU 訪問同步
dma_buf_begin_cpu_access(dmabuf, DMA_FROM_DEVICE);
// CPU 訪問緩沖區
dma_buf_end_cpu_access(dmabuf, DMA_FROM_DEVICE);
4.4 用戶空間 mmap
mmap(fd, ...); // 通過 fd 直接 mmap 到用戶空間
5. dma-buf 的同步機制
5.1 dma_resv 與 fence
-
dma-buf 通過?
struct dma_resv
?管理同步 fence,協調多設備并發訪問。 -
Exporter/Importer 在讀寫緩沖區前后添加/等待 fence,保證數據一致性。
-
支持隱式同步(如 GPU/顯示管線)和顯式同步(如用戶空間 fence)。
5.2 begin_cpu_access/end_cpu_access
-
在 CPU 訪問前后,需調用?
begin_cpu_access
/end_cpu_access
,由 exporter 實現 cache flush、內存屏障等操作,保證數據一致性。
6. dma-buf 的典型應用場景
6.1 GPU-顯示管線零拷貝
-
GPU 渲染輸出幀緩沖區,通過 dma-buf fd 傳遞給顯示控制器(DRM/KMS),實現零拷貝顯示。
6.2 攝像頭-ISP-GPU 協作
-
攝像頭驅動分配幀緩沖區,ISP 處理后通過 dma-buf fd 傳遞給 GPU 進行后處理或 AI 推理。
6.3 多媒體編解碼
-
VPU 解碼器輸出緩沖區,通過 dma-buf fd 傳遞給 GPU/顯示/AI 單元,實現高效視頻播放和處理。
6.4 用戶空間跨進程共享
-
用戶空間應用通過 dma-buf fd 在不同進程間共享大塊數據(如圖像、視頻幀、AI 張量等)。
7. dma-buf 的內核實現細節
7.1 文件描述符與引用計數
-
每個 dma-buf 對象都對應一個匿名文件(anon_inode),通過 fd 傳遞和引用計數。anon_inode技術參見博文:Linux 內核 anon_inode 機制詳解與應用。
-
內核通過?
get_dma_buf
/dma_buf_put
?管理生命周期。
7.2 設備 attach/detach
-
每個 importer attach 時,exporter 可檢查設備兼容性、DMA 約束等,拒絕不支持的設備。
-
detach 時清理相關資源。
7.3 映射與同步
-
map/unmap_dma_buf 負責將緩沖區映射到 importer 設備地址空間,支持多種內存類型和 DMA 方向。
-
begin/end_cpu_access 負責 cache flush、內存屏障等同步操作。
7.4 poll/epoll 支持
-
dma-buf 支持 poll/epoll 機制,用戶空間可通過 poll/epoll 監控緩沖區 fence 狀態,實現異步事件通知。
8. 總結
-
dma-buf 是 Linux 內核支持異構系統、跨設備零拷貝緩沖區共享的核心機制。
-
通過標準化的導出、導入、映射、同步等接口,極大簡化了驅動開發和系統集成。
-
支持多種內存類型、同步機制和異步事件通知,適應復雜硬件和高性能場景。
-
正確實現和使用 dma-buf 能顯著提升系統性能、帶寬利用率和開發效率。