第10章 无持久存储的文件系统 (3)

目录

[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介绍:

作用:

  1. 内核调试。

  2. 收集内核和应用程序的性能信息,如函数执行时间、调用次数等。

原理:

在指定函数中插入探测点,可在探测点前或探测点后执行对应回调函数。

注意:

需要硬件架构支持。

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跟踪网络流量。

  1. 跟踪TCP连接事件:

使用Kprobe在内核TCP连接函数中插入断点,当TCP连接建立或关闭时,将信息记录到顺序文件中。

记录的信息包括:源地址、目标地址、连接建立 / 关闭时间戳等。

  1. 跟踪收发包:

在收发包函数中插入断点,当有数据传输时,记录相关信息到顺序文件中。

记录的信息包括:源地址、目标地址、数据包大小、协议类型等信息。

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);

};

10.4 小结

相关推荐
林_学几秒前
Docker Desktop 全卸了,新项目上线从3天缩短到3分钟
运维·docker·容器
陈平安Java and C1 分钟前
Docker镜像原理
运维·docker·容器
爱吃山竹的大肚肚2 分钟前
Nginx 最核心和常用的命令
java·运维·服务器·前端·nginx
程序员在线炒粉8元1份顺丰包邮送可乐3 分钟前
Docker 部署PaddleOCR 实战教程(含离线模型、接口调用、排障)
运维·docker·ai·容器
天上飞的粉红小猪4 分钟前
Socket UDP编程
linux·网络协议·udp
尼古拉斯·纯情暖男·天真·阿玮5 分钟前
实验四 恶意软件实验
网络·安全·智能路由器
文亭湖畔程序猿6 分钟前
PVE 基础环境初始化与 Debian Cloud-Init 部署记录
网络·数据库·debian
沛沛老爹6 分钟前
Web开发者进阶AI架构:Agent Skills与MCP的企业级架构权衡实战
java·人工智能·架构·llm·llama·rag
init_23618 分钟前
【HCIE-05】OSPFV3
网络
想用offer打牌13 分钟前
一站式了解全局分布式生成ID方案
分布式·后端·面试·架构·系统架构·开源