目录
[10.2 简单文件系统](#10.2 简单文件系统)
[10.2.1 顺序文件](#10.2.1 顺序文件)
[10.2.2 用libfs编写文件系统](#10.2.2 用libfs编写文件系统)
[10.2.3 调试文件系统](#10.2.3 调试文件系统)
[10.2.4 伪文件系统](#10.2.4 伪文件系统)
[10.3 sysfs](#10.3 sysfs)
[10.3.1 概述](#10.3.1 概述)
[10.3.2 数据结构](#10.3.2 数据结构)
[10.3.3 装载文件系统](#10.3.3 装载文件系统)
[10.3.4 文件和目录操作](#10.3.4 文件和目录操作)
[10.3.5 向sysfs添加内容](#10.3.5 向sysfs添加内容)
[10.4 小结](#10.4 小结)
本专栏文章将有70篇左右,欢迎+关注,查看后续文章。
10.2 简单文件系统
如:libfs,seq_file,debugfs。
10.2.1 顺序文件
读写 proc 文件时,默认只使用一页内存。若proc文件太大,则用 seq_file。
seq_file优点:
不需要开发者直接管理保存数据的内存缓冲区。
简化了向用户空间输出内核数据。
1. 编写顺序文件处理函数
proc_create("netlink", 0, net->proc_net, &netlink_seq_fops);
struct file_operations netlink_seq_fops = {
.open = netlink_seq_open,
.read = seq_read,
//将调用struct seq_operations 中 start,next,stop,show等函数指针。
.llseek = seq_lseek,
};
struct seq_operations netlink_seq_ops = {
.start = netlink_seq_start, //开始读数据项。
.stop = netlink_seq_stop, //停止数据项。
.next = netlink_seq_next, //遍历下一个要处理的数据项。
.show = netlink_seq_show, //打印数据项到临时缓冲区。
};
若 file_operations 中 .llseek = no_llseek() ;
表示设备无法seek。
Kprobe介绍:
作用:
-
内核调试。
-
收集内核和应用程序的性能信息,如函数执行时间、调用次数等。
原理:
在指定函数中插入探测点,可在探测点前或探测点后执行对应回调函数。
注意:
需要硬件架构支持。
struct kprobe {
kprobe_opcode_t *addr; // 探测点位置。
kprobe_pre_handler_t pre_handler; // 探测指令被执行前的回调。
kprobe_post_handler_t post_handler; // 探测指令执行完毕后的回调。
kprobe_fault_handler_t fault_handler; // 当内存访问出错时被调用。
}
struct file_operations debugfs_kprobes_operations = {
.open = kprobes_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
struct seq_operations kprobes_seq_ops = {
.start = kprobe_seq_start,
.next = kprobe_seq_next, // 偏移+1=索引+1。
.stop = kprobe_seq_stop, // 什么也不做。
.show = show_kprobe_addr, // 生成文件内容。
};
int kprobes_open(struct inode *inode, struct file *filp)
{
return seq_open(filp, &kprobes_seq_ops);
}
Kprobe将事件发生时将相关数据记录到文件中。
举例:
使用Kprobe跟踪网络流量。
- 跟踪TCP连接事件:
使用Kprobe在内核TCP连接函数中插入断点,当TCP连接建立或关闭时,将信息记录到顺序文件中。
记录的信息包括:源地址、目标地址、连接建立 / 关闭时间戳等。
- 跟踪收发包:
在收发包函数中插入断点,当有数据传输时,记录相关信息到顺序文件中。
记录的信息包括:源地址、目标地址、数据包大小、协议类型等信息。
Jprobe:Kprobe一个扩展。
编程举例:
struct jprobe tcp_conn_open_probe = {
.entry = (kprobe_opcode_t *) tcp_conn_open, //自定义的断点处理函数。
.kp = {
.symbol_name = "tcp_v4_connect", //需要跟踪的内核函数。
},
};
struct jprobe tcp_conn_close_probe = {
.entry = (kprobe_opcode_t *) tcp_conn_close,
.kp = {
.symbol_name = "inet_csk_destroy_sock",
},
};
int tcp_conn_init(void)
{
register_jprobe( &tcp_conn_open_probe );
register_jprobe( &tcp_conn_close_probe );
}
void tcp_conn_exit(void)
{
// 取消注册Kprobe
unregister_jprobe(&tcp_conn_open_probe);
unregister_jprobe(&tcp_conn_close_probe);
}
10.2.2 用libfs编写文件系统
libfs:一个库,用于创建特定用途的小型文件系统,适合无后备存储器。
编程举例:
struct file_operations simple_dir_operations = {
.open = dcache_dir_open,
.release = dcache_dir_close,
.llseek = dcache_dir_lseek,
.read = generic_read_dir,
.readdir = dcache_readdir,
.fsync = noop_fsync,
};
struct inode_operations simple_dir_inode_operations = {
.lookup = simple_lookup;
};
10.2.3 调试文件系统
DebugFS:
原理:
基于libfs实现。
使用场景:
快速查看或修改模块/内核的变量,无需重新编译内核或模块。
对应目录:
/sys/kernel/debug
编译选项:
CONFIG_DEBUG_FS
编程接口:
debugfs_kprobe_init
debugfs_create_file
debugfs_create_dir
debugfs_create_symlink
10.2.4 伪文件系统
如:bdev文件系统。
bdev作用:
集群块设备所有的inode,只有内核可见。
struct file_system_type bd_type = {
.name = "bdev",
.mount = bd_mount,
.kill_sb = kill_anon_super,
}
struct dentry *bd_mount(struct file_system_type *fs_type, int flags, char *dev_name, void *data)
{
return mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, BDEVFS_MAGIC);
}
10.3 sysfs
作用:
向用户层导出内核对象。
显示kobject拓扑。
提供装载点/sys。
10.3.1 概述
kobject被层次化组织。
如果一个kobject没有父对象,将其放置到所在kset所属的kobject对应目录中。
每个kobject表示sysfs中一个目录。而attribute表示sysfs中一个文件。
kobject_add函数
作用:导出kobject到sys文件系统。
10.3.2 数据结构
属性:
struct attribute { //代表sysfs中一个文件
const char *name;
umode_t mode; //文件访问权限。
};
10.3.3 装载文件系统
struct file_system_type sysfs_fs_type = {
.name = "sysfs",
.mount = sysfs_mount,
.kill_sb = sysfs_kill_sb,
};
sysfs_mount -> sysfs_fill_super
创建根目录的inode
int sysfs_fill_super(struct super_block *sb, void *data, int silent)
{
inode = sysfs_get_inode(sb, &sysfs_root);
//inode->i_fop = &sysfs_file_operations;
}
sysfs_file_operations:后续介绍
10.3.4 文件和目录操作
struct file_operations sysfs_file_operations = {
.read = sysfs_read_file,
//调用ops->show(kobj, attr_sd->s_attr.attr, buffer->page);
.write = sysfs_write_file,
.open = sysfs_open_file,
}
struct kobj_type brport_ktype = {
.sysfs_ops = &brport_sysfs_ops,
};
ops->show();为不同文件自定义,如/sys/bridge
struct sysfs_ops brport_sysfs_ops = {
.show = brport_show, //调用brport_attr->show(p, buf);
.store = brport_store,
};
而 brport_attr->show(p, buf); 是/sys/bridge下不同文件各自定义的,如:
BRPORT_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router, store_multicast_router)
10.3.5 向sysfs添加内容
struct kobj_attribute {
struct attribute attr; //包括文件名,文件权限。
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count);
};