執行人: hungyuhang
專題解說錄影
Skipping BTF generation for /home/hungyuhang/linux2024/vcam/vcam.ko due to unavailability of vmlinux
不是很確定這個訊息代表什麼。
根據BPF Type Format (BTF)
BTF (BPF Type Format) is the metadata format which encodes the debug info related to BPF program/map
BTF file 是和 BPF(Berkerly packet filter)相關的訊息,請問這樣的 warning 對你的專案有影響嗎?
hungyuhang
依我目前的理解,如果 BTF generation 被跳過的話,影響應該是 Linux 無法在我的核心模組裡面插入一些 debug message ,而這些 debug message 是當我們在用 eBPF 技術去對核心模組進行 debug 的時候會被用到。
st10740
試著將 vcam 運行久一點再來看結果(使用這個測試來播放單色輸出的影片約十分鐘),從結果發現隨著時間拉長, vcam 在呼叫 __check_object_size() 跟 _copy_from_user() 的時候也開始出現 memory leak 的狀況。
想請問 __check_object_size() 和 _copy_from_user() 之間是否有關連性呢? 因為在你提供的 stack trace 上似乎沒有看到 __check_object_size()。
hungyuhang
在 vcam 程式碼裡面,當把使用者傳入 Framebuffer API 的資料從 user-space 複製到 kernel-sapce 的時候會使用 copy_from_user() 這個函式,以下式這個函式的程式碼:static __always_inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { if (check_copy_size(to, n, false)) n = _copy_from_user(to, from, n); return n; }
其中,
check_copy_size()
會間接的呼叫到 __check_object_size() ,所以當程式碼呼叫copy_from_user()
的時候,在check_copy_size()
回傳True
的前提下,__check_object_size()
跟_copy_from_user()
就會依序被呼叫到。
改進 vcam 裝置驅動程式,使其可在新版 Linux 核心運作、通過 V4L2 測試,並支援 DMABUF。
vcam 是個針對 Linux 核心開發的虛擬攝影機裝置,全部程式碼僅 1 千 5 百行,從而可理解 V4L2 (video fro Linux APIs, version 2) 的使用和 Linux 多媒體架構。開發一個虛擬的攝影機裝置除了理解 Linux 核心設計外,也有資訊安全的幫助,例如你可以安插相關程式碼,紀錄有哪些應用程式偷偷啟動攝影機,但過程中又不會揭露真正的隱私。
理解 vcam 的運作原理: 筆記
提交 pull request 並針對近期 Linux 核心進行修正
使用 make
命令編譯核心模組,會出現以下錯誤:
$ make
make -C /lib/modules/6.5.0-35-generic/build M=/home/hungyuhang/linux2024/vcam modules
make[1]: Entering directory '/usr/src/linux-headers-6.5.0-35-generic'
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0
You are using: gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0
CC [M] /home/hungyuhang/linux2024/vcam/module.o
CC [M] /home/hungyuhang/linux2024/vcam/control.o
In file included from ./include/linux/linkage.h:7,
from ./arch/x86/include/asm/cache.h:5,
from ./include/linux/cache.h:6,
from ./arch/x86/include/asm/current.h:9,
from ./include/linux/sched.h:12,
from ./include/linux/ratelimit.h:6,
from ./include/linux/dev_printk.h:16,
from ./include/linux/device.h:15,
from /home/hungyuhang/linux2024/vcam/control.c:3:
/home/hungyuhang/linux2024/vcam/control.c: In function ‘create_control_device’:
./include/linux/export.h:29:22: error: passing argument 1 of ‘class_create’ from incompatible pointer type [-Werror=incompatible-pointer-types]
29 | #define THIS_MODULE (&__this_module)
| ~^~~~~~~~~~~~~~~
| |
| struct module *
/home/hungyuhang/linux2024/vcam/control.c:267:38: note: in expansion of macro ‘THIS_MODULE’
267 | ctldev->dev_class = class_create(THIS_MODULE, dev_name);
| ^~~~~~~~~~~
In file included from ./include/linux/device.h:31:
./include/linux/device/class.h:230:54: note: expected ‘const char *’ but argument is of type ‘struct module *’
230 | struct class * __must_check class_create(const char *name);
| ~~~~~~~~~~~~^~~~
/home/hungyuhang/linux2024/vcam/control.c:267:25: error: too many arguments to function ‘class_create’
267 | ctldev->dev_class = class_create(THIS_MODULE, dev_name);
| ^~~~~~~~~~~~
./include/linux/device/class.h:230:29: note: declared here
230 | struct class * __must_check class_create(const char *name);
| ^~~~~~~~~~~~
cc1: some warnings being treated as errors
make[3]: *** [scripts/Makefile.build:251: /home/hungyuhang/linux2024/vcam/control.o] Error 1
make[2]: *** [/usr/src/linux-headers-6.5.0-35-generic/Makefile:2039: /home/hungyuhang/linux2024/vcam] Error 2
make[1]: *** [Makefile:234: __sub-make] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-6.5.0-35-generic'
make: *** [Makefile:14: kmod] Error 2
觀察錯誤訊息,可以發現錯誤是來自於 class_create()
呼叫。這個函式只需要一個引數,但是程式碼中卻對這個函式傳入了兩個引數。
會出現這樣的錯誤訊息,是因為 Linux Kernel API 在 Linux v6.4 之後的版本更新了對 create_class()
函式的呼叫方式。
更新前的 API 呼叫方式:
class_create(owner, name)
更新後的 API 呼叫方式:
class_create(name)
對於 Linux Kernel API 的詳細更改可以參考 Linux kernel commit 1aaba11 。
為了因應以上變動,需要在 vacm 專案的 control.c
內加上以下程式碼:
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)
+ ctldev->dev_class = class_create(dev_name);
+ #else
ctldev->dev_class = class_create(THIS_MODULE, dev_name);
+ #endif
當核心版本大於或等於 v6.4 的時候,就會用新版 Kernel API 的方式去呼叫 create_class()
,反之則使用原來的方式去呼叫。
提交紀錄: sysprog21#38
將 Linux kernel 版本更新到 6.8.0
之後,編譯 vcam 核心組件時又出現了新的問題:
make -C /lib/modules/6.8.0-35-generic/build M=/home/hungyuhang/linux2024/vcam modules
make[1]: Entering directory '/usr/src/linux-headers-6.8.0-35-generic'
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc-13 (Ubuntu 13.2.0-23ubuntu4) 13.2.0
You are using: gcc-13 (Ubuntu 13.2.0-23ubuntu4) 13.2.0
CC [M] /home/hungyuhang/linux2024/vcam/module.o
CC [M] /home/hungyuhang/linux2024/vcam/control.o
CC [M] /home/hungyuhang/linux2024/vcam/device.o
CC [M] /home/hungyuhang/linux2024/vcam/videobuf.o
/home/hungyuhang/linux2024/vcam/videobuf.c: In function ‘vcam_out_videobuf2_setup’:
/home/hungyuhang/linux2024/vcam/videobuf.c:138:6: error: ‘struct vb2_queue’ has no member named ‘min_buffers_needed’
138 | q->min_buffers_needed = 2;
| ^~
make[3]: *** [scripts/Makefile.build:243: /home/hungyuhang/linux2024/vcam/videobuf.o] Error 1
make[2]: *** [/usr/src/linux-headers-6.8.0-35-generic/Makefile:1926: /home/hungyuhang/linux2024/vcam] Error 2
make[1]: *** [Makefile:240: __sub-make] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-6.8.0-35-generic'
make: *** [Makefile:14: kmod] Error 2
錯誤來自於 struct vb2_queue
結構體沒有 min_buffers_needed
這個成員。
參考 Linux kernel commit 80c2b40 ,可以發現 Linux 核心在 v6.8 之後就把 min_buffers_needed
改名成 min_queued_buffers
。所以只要將成員名稱做修改就好。
排除上述問題之後,重新執行了一次 make ,但編譯時出現另一個問題:
hungyuhang@UX434FQ:~/linux2024/vcam$ make
make -C /lib/modules/6.8.0-35-generic/build M=/home/hungyuhang/linux2024/vcam modules
make[1]: Entering directory '/usr/src/linux-headers-6.8.0-35-generic'
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc-13 (Ubuntu 13.2.0-23ubuntu4) 13.2.0
You are using: gcc-13 (Ubuntu 13.2.0-23ubuntu4) 13.2.0
CC [M] /home/hungyuhang/linux2024/vcam/module.o
CC [M] /home/hungyuhang/linux2024/vcam/control.o
CC [M] /home/hungyuhang/linux2024/vcam/device.o
CC [M] /home/hungyuhang/linux2024/vcam/videobuf.o
CC [M] /home/hungyuhang/linux2024/vcam/fb.o
/home/hungyuhang/linux2024/vcam/fb.c: In function ‘vcamfb_init’:
/home/hungyuhang/linux2024/vcam/fb.c:405:19: error: ‘FBINFO_FLAG_DEFAULT’ undeclared (first use in this function); did you mean ‘FAULT_FLAG_DEFAULT’?
405 | info->flags = FBINFO_FLAG_DEFAULT;
| ^~~~~~~~~~~~~~~~~~~
| FAULT_FLAG_DEFAULT
/home/hungyuhang/linux2024/vcam/fb.c:405:19: note: each undeclared identifier is reported only once for each function it appears in
make[3]: *** [scripts/Makefile.build:243: /home/hungyuhang/linux2024/vcam/fb.o] Error 1
make[2]: *** [/usr/src/linux-headers-6.8.0-35-generic/Makefile:1926: /home/hungyuhang/linux2024/vcam] Error 2
make[1]: *** [Makefile:240: __sub-make] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-6.8.0-35-generic'
make: *** [Makefile:14: kmod] Error 2
這次的錯誤是來自於 Liunx 核心在 v6.6 之後就將 FBINFO_FLAG_DEFAULT
巨集給移除了,詳細可以參考 Linux kernel commit 0444fa3 。
關於如何更改程式碼,我參考了這個範例在 FBINFO_FLAG_DEFAULT
被移除時所做的更動,這邊的作法是直接不賦予 fb_info.flags
值。但他們能這樣做的前提都是他們在創立 fb_info
的 struct 的時候是使用 framebuffer_alloc() ,這個函式會直接把整個 fb_info
的 struct 裡面各個成員的值給設為預設值。
但是在 vcam 裡面, fb_info
是用 vmalloc()
去分配記憶體位址,所以無法確保 fb_info
裡面的所有欄位被設定為適當的預設值。所以我在這次的 vcam 程式碼更動也使用了 framebuffer_alloc() 函式來初始化 fb_info
的 struct 。
修改之後再重新執行 make ,可以編譯成功,但是在編譯的輸出裡面有一行訊息:
Skipping BTF generation for /home/hungyuhang/linux2024/vcam/vcam.ko due to unavailability of vmlinux
不是很確定這個訊息代表什麼。
提交紀錄:sysprog21#39
如何快速找到核心程式碼在什麼時候被更改?
善用 git log 和 git blame
若遇到測試案例失敗的狀況,修正並提交 pull request。
更新相關的文件
先使用 vcam 專案內的 vcam-util
工具程式確認 video 裝置的名稱:
$ sudo ./vcam-util -l
Available virtual V4L2 compatible devices:
1. fb1(640,480,1/1,rgb24) -> /dev/video4
使用以下命令對 vcam 做測試:
$ sudo v4l2-compliance -d /dev/video4 -f
以下節錄自測試的輸出結果,可以看到所有測試都有通過:
...
Total for vcam device /dev/video4: 48, Succeeded: 48, Failed: 0, Warnings: 0
使用 kmodleak 找出記憶體操作的缺失並修正
首先照著 kmodleak readme 裡面的指引進行編譯。
編譯完後,執行 kmodleak :
$ sudo ./kmodleak vcam
並且在另一個終端將 vcam 掛載到核心上面:
$ sudo insmod vcam.ko
當想要停止測試時,將 vcam 卸載:
$ sudo rmmod vcam
vcam 被卸載後, kmodleak 就會自動停止,並且產生報告。
以下節錄自 kmodleak 產生的報告:
關於怎麼看報告可以看這篇
$ sudo ./kmodleak vcam
using page size: 4096
Tracing module memory allocs... Unload module (or hit Ctrl-C) to end
module 'vcam' loaded
module 'vcam' unloaded
27 stacks with outstanding allocations:
32768 bytes in 1 allocations from stack
addr = 0x15fb48 size = 32768
0 [<ffffffffaf64edf4>] __alloc_pages+0x264
1 [<ffffffffaf64edf4>] __alloc_pages+0x264
2 [<ffffffffaf657b18>] allocate_slab+0xa8
3 [<ffffffffaf657e28>] new_slab+0x38
4 [<ffffffffaf65ae35>] ___slab_alloc+0x435
5 [<ffffffffaf65d2c0>] kmalloc_trace+0x310
6 [<ffffffffafbc5142>] do_register_framebuffer+0x272
7 [<ffffffffafbc51f1>] register_framebuffer+0x21
8 [<ffffffffc51024a2>] crypto_ccm_module_init+0x5492
9 [<ffffffffc5101191>] crypto_ccm_module_init+0x4181
10 [<ffffffffc50ff307>] crypto_ccm_module_init+0x22f7
11 [<ffffffffc5251045>] __kstrtabns_nvKmsKapiGetFunctionsTable+0x8a02
12 [<ffffffffaf2019bb>] do_one_initcall+0x5b
13 [<ffffffffaf3f4380>] do_init_module+0xc0
14 [<ffffffffaf3f6281>] load_module+0xba1
...
上面訊息的意思是說,有一個 32768 bytes 的記憶體空間被配置但是卻沒有被釋放。而在這次測試期間,有偵測到 27 個沒有被釋放掉的記憶體配置。
在這些 stack trace 都沒有看到 vcam 的函式,不確定原因。
經過觀察, vcam 大多數的 memory leak 都來自於下面兩種:
video_register_device()
這類 Linux 提供的 driver 函式時所配置的。copy_from_user()
的時候會產生一些無法被釋放的記憶體而且大多數 memory leak 並不是每次都發生,上面那個 32768 bytes 的 memory leak 就是一個例子。
跟 akvcam 做比對
akvcam :
$ sudo ./kmodleak akvcam
using page size: 4096
Tracing module memory allocs... Unload module (or hit Ctrl-C) to end
module 'akvcam' loaded
module 'akvcam' unloaded
44 stacks with outstanding allocations:
vcam :
$ sudo ./kmodleak vcam
using page size: 4096
Tracing module memory allocs... Unload module (or hit Ctrl-C) to end
module 'vcam' loaded
module 'vcam' unloaded
27 stacks with outstanding allocations:
本來想要以 akvcam 作為範本來改善 vcam 在載入以及卸載模組時所產生的 memory leak ,但是發現 akvcam 也有一樣的問題,例如這兩個專案都無法釋放在呼叫 __video_register_device
時所配置的記憶體。
目前這邊遇到的問題,是從 stack trace 只能得知 vcam driver 在呼叫哪個 kernel api call 的時候配置的記憶體最後沒被釋放掉,但是沒有被釋放掉的原因卻難以追蹤。
以 __video_register_device
為例,我們可以得知核心在建立 video device 的時候配置了一些記憶體,但是當 vcam 呼叫相對應的 video_unregister_device
的時候,這些相對應的記憶體卻沒被釋放掉,推測有可能是下列原因:
但這些都只是推測,要實際知道原因的話可能需要花時間去看原始碼,或是有其他方式?
另外也有注意到配置的記憶體位置有分兩種:
32768 bytes in 1 allocations from stack
addr = 0x8b070 size = 32768
0 [<ffffffff8284edf4>] __alloc_pages+0x264
1 [<ffffffff8284edf4>] __alloc_pages+0x264
2 [<ffffffff82857b18>] allocate_slab+0xa8
...
128 bytes in 1 allocations from stack
addr = 0xffff98be4329d400 size = 128
0 [<ffffffff8285ceb3>] kmem_cache_alloc+0x253
1 [<ffffffff8285ceb3>] kmem_cache_alloc+0x253
2 [<ffffffff829bac55>] __kernfs_new_node+0x65
3 [<ffffffff829bc4c6>] kernfs_new_node+0x56
...
依照這份文件來看,數字小的記憶體位置(例如上面的 0x8b070
)是 user-space virtual memory ,數字大的(例如上面的 0xffff98be4329d400
)是 Kernel-space virtual memory 。
關於 memory mapping 的概念可以參考這篇以及這篇。
試著去追蹤其中一個 memory leak ,這邊選擇了呼叫 register_framebuffer()
時所產生的 memory leak :
32768 bytes in 1 allocations from stack
addr = 0x8b070 size = 32768
0 [<ffffffff8284edf4>] __alloc_pages+0x264
1 [<ffffffff8284edf4>] __alloc_pages+0x264
2 [<ffffffff82857b18>] allocate_slab+0xa8
3 [<ffffffff82857e28>] new_slab+0x38
4 [<ffffffff8285ae35>] ___slab_alloc+0x435
5 [<ffffffff8285d2c0>] kmalloc_trace+0x310
6 [<ffffffff82dc5142>] do_register_framebuffer+0x272
7 [<ffffffff82dc51f1>] register_framebuffer+0x21
8 [<ffffffffc54bc3d9>] rfcomm_tty_driver+0xb2d1
9 [<ffffffffc54bb0bd>] rfcomm_tty_driver+0x9fb5
10 [<ffffffffc54b92d7>] rfcomm_tty_driver+0x81cf
11 [<ffffffffc54c5045>] rfcomm_tty_driver+0x13f3d
12 [<ffffffff824019bb>] do_one_initcall+0x5b
13 [<ffffffff825f4380>] do_init_module+0xc0
14 [<ffffffff825f6281>] load_module+0xba1
以下是推測的程式執行方式:
do_register_framebuffer() 會用 kmalloc_trace() 為 fb_info->pixmap
配置一個記憶體位置,其中 kmalloc_trace()
會使用 slab 來取得記憶體。
從 slab 取得的記憶體應該是在 kernel memory space ,但是這個 memory leak 的 address 卻是 0x8b070
(位於 user-sapce )。
所以說這個 memory leak 的原因會是因為 slab allocator 不小心配置了錯誤的記憶體位置而導致的嗎?
經過觀察,如果配置記憶體的函式(例如 kmalloc()
vmalloc()
)的後面有接著呼叫 __alloc_pages()
的話,那它 leak 的 memory address 就會是在 user-space 裡面的,反之如果沒有的話,那麼 leak 的 memory address 就會是在 kernel space 裡面。
copy_from_user()
時產生的 memory leak試著將 vcam 運行久一點再來看結果(使用這個測試來播放單色輸出的影片約十分鐘),從結果發現隨著時間拉長, vcam 在呼叫 __check_object_size() 跟 _copy_from_user() 的時候也開始出現 memory leak 的狀況。
3072 bytes in 3 allocations from stack
addr = 0xffff98bebedd8800 size = 1024
addr = 0xffff98be55403800 size = 1024
addr = 0xffff98be75e7e400 size = 1024
0 [<ffffffff8285d212>] kmalloc_trace+0x262
1 [<ffffffff8285d212>] kmalloc_trace+0x262
2 [<ffffffff82f7ec97>] free_iova_fast+0x167
3 [<ffffffff82f7a7d0>] fq_ring_free_locked+0x50
4 [<ffffffff82f7b30d>] fq_flush_timeout+0x6d
5 [<ffffffff82601d87>] call_timer_fn+0x27
6 [<ffffffff82602132>] __run_timers+0x262
7 [<ffffffff826021fd>] run_timer_softirq+0x1d
8 [<ffffffff8363fbce>] __do_softirq+0xde
9 [<ffffffff825090b7>] __irq_exit_rcu+0xd7
10 [<ffffffff8250941e>] irq_exit_rcu+0xe
11 [<ffffffff83624882>] sysvec_apic_timer_interrupt+0x92
12 [<ffffffff83800f4b>] asm_sysvec_apic_timer_interrupt+0x1b
13 [<ffffffff82c60c17>] _copy_from_user+0x27
14 [<ffffffffc54bbde3>] rfcomm_tty_driver+0xacdb
15 [<ffffffff82dcba8f>] fb_write+0x6f
16 [<ffffffff828e168d>] vfs_write+0xfd
17 [<ffffffff828e1dd3>] ksys_write+0x73
18 [<ffffffff828e1e89>] __x64_sys_write+0x19
19 [<ffffffff824040be>] x64_sys_call+0x7e
20 [<ffffffff8361dc3f>] do_syscall_64+0x7f
21 [<ffffffff83800130>] entry_SYSCALL_64_after_hwframe+0x78
為什麼 calling stack 的記憶體位址不是遞減的?
_copy_from_user() 的功能(參考這個網址):就是把資料從 user-space 複製到 kernel space 。
但是為什麼 copy_from_user()
需要去配置記憶體?
從 stack trace 來看,在呼叫 copy_from_user()
之後,會做以下的事情:
但是在 vcam 的使用情境, framebuffer 理論上並沒有用到 DMA ,那為什麼會呼叫到 DMA 相關的東西?猜想:
有突發奇想把配置 framebuffer 記憶體位置的 vmalloc(size)
換成 kmalloc(size, GFP_KERNEL)
但是 memory leak 依然存在。
找不到 memory leak 的原因,這個部份先暫緩。
參考 HotMercury 以及 jason50123 的筆記中排除記憶體處理的缺失章節,他們使用了 rcu_barrier() 來解決 memory leak 的問題。( rcu_barrier 的介紹: rcubarrier.txt)
具體來說,他們在呼叫 kmem_cache_destroy() 後,又再呼叫了一個 rcu_barrier() 來解決記憶體來不及被釋放掉的問題。實際改動可以參考 RoyWFHuang的這個commit
參照上述的更動,我在將 vcam 卸載時會呼叫到的部份函式呼叫之後加上了 rcu_barrier() 。以下是程式碼改動:
// function vcamfb_destroy in fb.c
info = fb_data->info;
if (info) {
unregister_framebuffer(info);
+ rcu_barrier();
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
}
// function destroy_vcam_device in device.c
if (vcam->sub_thr_id)
kthread_stop(vcam->sub_thr_id);
vcamfb_destroy(vcam);
+ rcu_barrier();
mutex_destroy(&vcam->vcam_mutex);
video_unregister_device(&vcam->vdev);
v4l2_device_unregister(&vcam->v4l2_dev);
+ rcu_barrier();
kfree(vcam);
}
// function free_control_device in control.c
static void free_control_device(struct control_device *dev)
{
size_t i;
for (i = 0; i < dev->vcam_device_count; i++)
destroy_vcam_device(dev->vcam_devices[i]);
kfree(dev->vcam_devices);
device_destroy(dev->dev_class, dev->dev_number);
class_destroy(dev->dev_class);
+ rcu_barrier();
cdev_del(&dev->cdev);
unregister_chrdev_region(dev->dev_number, 1);
kfree(dev);
}
使用這個測試來播放單色輸出的影片約五分鐘來測試兩個不同的版本。
以下是兩個不同版本程式碼用 kmodleak 做測量的部份結果:
$ sudo ./kmodleak vcam
using page size: 4096
Tracing module memory allocs... Unload module (or hit Ctrl-C) to end
module 'vcam' loaded
module 'vcam' unloaded
31 stacks with outstanding allocations:
...
$ sudo ./kmodleak vcam
using page size: 4096
Tracing module memory allocs... Unload module (or hit Ctrl-C) to end
module 'vcam' loaded
module 'vcam' unloaded
10 stacks with outstanding allocations:
...
可以看到,加了 rcu_barrier() 的版本的 memory leak 的數量明顯減少了,但為什麼會減少的原因還有待研究。
參考 akvcam
兩專案差異:
akvcam 可以把 VB2_DMABUF
加入 struct vb2_queue
的 io_modes
成員(使用 |
運算子)。
vcam 直接把 struct vb2_queue
的 io_modes
成員的值設為 VB2_MMAP | VB2_USERPTR | VB2_READ
先嘗試將 vcam 的 vb2_queue.io_modes 加入 VB2_DMABUF
:
- q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF;
然後運行 vcam 核心模組,核心模組可以正常運作。
如何確認 vb2 模組真的有用 DMA ?