Ftrace 通过操作调试 fs 文件来控制。但这怎么可能呢?内核如何知道此文件中的写入并启动其所需的操作?例如,如果将1写入tracing_on,内核将打开跟踪。它是否与特殊文件结构或内核订阅 debugfs 的更改有关,或者我遗漏了一些明显的东西?
答案1
我想我找到了。根据这个关联 在内核中,字符类型设备由struct cdev表示,该结构体用于在系统中注册它。大多数驱动程序操作使用三个重要的结构:struct file_operations、struct file 和 struct inode。如上所述,字符设备驱动程序接收用户通过设备类型文件发出的未更改的系统调用。因此,字符设备驱动程序的实现意味着实现特定于文件的系统调用:open、close、read、write、lseek、mmap 等。这些操作在 struct file_operations 结构的字段中描述:
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
[...]
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
[...]
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
[...]
所以我们可以用我们想要的函数初始化上面的函数指针。例如对于tracing_on,这是kernel/trace/trace.c中的初始化,并且这些函数在同一文件中实现:
static const struct file_operations rb_simple_fops = {
.open = tracing_open_generic_tr,
.read = rb_simple_read,
.write = rb_simple_write,
.release = tracing_release_generic_tr,
.llseek = default_llseek,
};
这也是创建此目录的代码:
trace_create_file("tracing_on", 0644, d_tracer,
tr, &rb_simple_fops);