Linux内核编程--字符设备文件,进行进程间通信,弄清open

2022-01-19  本文已影响0人  鹏_921010

前言:进程间通信有:

socket ,  共享内存, 消息队列,信号量,信号,环境变量等

一、字符设备驱动框架流程:

字符设备驱动框架流程:

二、实列代码跑的效果:

发送数据 接收数据 Makefile 我们可以单独看mmap和poll

poll的实现主要是使用的内核,驱动程序常用的等待队列

关于系统调用:(以调用open函数)

系统调用触发中断,中断会去找系统调用表通过基地址寻址调用内核sys_open, 然后调用file_operations里的函数。

open与channel_open有什么联系??

1. 调用open

2.触发int ox80的中断,中断的入口函数system_call

3.在system_call里面,调用sys_call_table,系统调用表

4.在unistd.h里,设置系统调用ID, (fork id 2 , read id is 3)

5. sys_call_table通过基地址寻址,sys_call_table+%eax*4-->

6. 调用内核函数sys_open

7. sys_调用file_operations对应的接口

fd位于应用层,而file位于内核层,他们都同属进程相关的概念。在linux中,同一个文件(对应于唯一的inode)可以被不同的进程打开多次,而每次打开都会获得file数据结构。而每个进程都会维护一个已经打开的file数组,fd就是对应file结构的数组下标。因此,file和fd在进程范围内是一一对应的关系。

inode ------- file_ops

fd ------file数组对应,根据fd找到file->file_ops

struct file {

    const struct file_operations *f_op;

     unsigned int f_flags;// 可读,可写

}

系统调用open,能找到channel_open().流程是这样:open("/dev/ntychannel",) --->每个进程都会被分配个file结构体,---》file结构体里又有个inode, 但是每个文件都有一个inode,inode里有设备号,根据96和0,找到是哪个设备,---》然后通过cdev_init & cdev_add, 把设备cdev和file_operations联系起来。

下面这幅图比较形象:

mknod /dev/ntychennel c 96 0

c:字符设备  96:主设备号   0:次设备号

cat /proc/devices:   查看设备号

mknod 用指定名称产生一个FIFO(命名管道),字符专用或块专用文件

上面3张图是一张,因为屏幕小,截不了

也可以跟下内核的代码:

select内部也是调用了poll mmap 虚拟内存结构图

编译生成的ko文件,sudo insmod ntychannel.ko 报错如下:

内核对新加的木块需要验证,现在是验证失败,因为是ubuntu系统上,内核没有编译。最上的跑的结果是我在ubuntu14.04的结果,因为内核从哪个版本开始(不记得版本),就需要验证了

获取公钥私钥:https://wiki.gentoo.org/wiki/Signed_kernel_module_support#Enabling_module_signature_verification

openssl req -new -nodes -utf8 -sha512 -days 36500 -batch -x509 -config x509.genkey -outform PEM -out signing_key.pem signing_key.x509  -keyout signing_key.priv

sudo su 

openssl req -new -nodes -utf8 -sha512 -days 36500 -batch -x509 -config x509.genkey -outform DER -out signing_key.x509 -keyout signing_key.pem

对Ko文件加验证

可以思考下:虚拟文件系统(VFS)对mmap前期做了哪些操作?

1 https://www.leviathan.vip/2019/01/13/mmap%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/   讲解很细,还是需要自己去看下内核源码,然后与该文档进行对照

Linux内核提供了remap_pfn_range函数: 来实现将内核空间的内存映射到用户空间

还有就是内核和驱动常用的等待队列的函数的说明(有点像条件等待)。

几个API是POLL实现的调用的几个内核函数:

wait_event_interruptible(channel->inq, have_data);

在进程执行过程中,有时候需要等待某个条件满足而进行进程阻塞。

常用的一种方法就是让调用者进程暂时挂起,直到目标进程返回结果后,再唤醒等待的进程。

wake_up(&channel->inq); 唤醒等待队列中进程

poll_wait(): 把本进程挂入某个队列

mknod: mknod 函数用于创建各种类型的文件,包括普通文件、特殊文件以及设备文件

设备文件是文件系统中代表设备的特殊文件。与普通的文件相比,设备文件在磁盘(或宿主文件系统所的在其它设备)上只占用一个索引节点,而没有任何用于存放数据的记录块与之相联系。当然,这是因为设备文件的目的并不在于存储和读取数据,而只在于为应用程序提供一条通向具体设备的途径,使应用程序可以跟具体设备建立起连接。

普通文件(以及某些特殊文件)可以通过系统调用 open 来创建,只要在调用参数中或上 O_CREAT 标志,就可以让open函数在目标文件不存在时先创建这个文件。当然也可通过调用 creat() 来直接创建文件,事实上 sys_creat() 就是通过 sys_open() 实现的。可是这两个系统调用都不能用来创建设备文件,因为设备文件的创建需要有一个参数来传递设备号,而 open 和 creat 函数都不包括这个参数。此时就是 mknod 函数存在的意义了。

二、自己实现一个文件系统,无存储文件系统

proc:虚拟文件系统,在linux系统中被挂载与/proc目录下。里面的文件包含了很多系统信息,比如cpu负载、 内存、网络配置和文件系统等等。我们可以通过内部文本流来查看进程信息(正在运行的各个进程的PID号也以目录名形式存在/proc目录下)和机器的状态.

tmpfs:虚拟内存文件系统,使用内存作为临时存储分区,掉电之后会丢失数据,创建时不需要使用mkfs等格式化 。

1.tmpfs挂载:

mount  -t  tmpfs  -o  size=20M tmpfs  /tmp

df -h

使用/etc/fstab条目:tmpfs  /tmp  tmpfs  default  0  0

2.tmpfs使用:

用来存储临时生成信息

正常使用挂载目录:创建文件,存储信息,删除文件等

3.tmpfs作用

因为内存的访问速度高于flash,所以可以提高存储效率,避免对flash频繁读写(flash寿命有限)

devfs:设备文件,提供类似于文件的方法来管理位于/dev目录下的设备

sysfs:虚拟内存文件系统,2.6内核之前没有规定sysfs的标准挂载目录,但是在2.6之后就规定了要挂载到/sys目录下(针对以前的 sysfs 挂载位置不固定或没有标准被挂载,有些程序从 /proc/mounts 中解析出 sysfs 是否被挂载以及具体的挂载点,这个步骤现在已经不需要了)。它的作用类似于proc,但除了与 proc 相同的具有查看和设定内核参数功能之外,还有为 Linux 统一设备模型作为管理之用。相比于 proc 文件系统,使用 sysfs 导出内核数据的方式更为统一,并且组织的方式更好。

与proc的比较:

sysfs 与 proc 相比有很多优点,最重要的莫过于设计上的清晰。一个 proc 虚拟文件可能有内部格式,如 /proc/scsi/scsi ,它是可读可写的,(其文件权限被错误地标记为了 0444 !,这是内核的一个BUG),并且读写格式不一样,代表不同的操作,应用程序中读到了这个文件的内容一般还需要进行字符串解析,而在写入时需要先用字符串格式化按指定的格式写入字符串进行操作;相比而言, sysfs 的设计原则是一个属性文件只做一件事情, sysfs 属性文件一般只有一个值,直接读取或写入。整个 /proc/scsi 目录在2.6内核中已被标记为过时(LEGACY),它的功能已经被相应的 /sys 属性文件所完全取代。新设计的内核机制应该尽量使用 sysfs 机制,而将 proc 保留给纯净的“进程文件系统”。

文件系统常用的数据结构

struct file_system_type 文件系统类型

struct super_block  超级块  文件系统的根

struct inode、struct inode_operations    索引节点

struct file 、struct  file_operations  文件信息

struct dentry   目录项

register_filesystem(&tinyfs_fs_type) ------->  tinyfs_mount(mount) ----> mount_nodev(fs_type, flags, data, tinyfs_fill_super)-------->tinyfs_fill_super------->inode_operations/file_operations ----->

inode_operations: create  lookup  mkdir rmdir unlink   具体实现

file_operations : read  write  readdir(ls)                        具体实现

mount -t proc proc /mnt  mount的流程

file  inode

file: 存贮的文件的内容

inode: 强调的是磁盘当中存贮的元数据

一个文件系统怎么样才能工作,有以下3个部分

1. insmod kingfs.ko               fingfs的文件系统加入全局的链表中

2. mount -t kingfs none /mnt

3. echo "111" > /mnt/a.txt   

mount_nodev(fs_type, flags, data, tinyfs_fill_super); //mount -t kingfs none /mnt

mount的时候,产生super_block

为什么在mount的就有?为何不是insmod ko的时候生成?

多个设备使用同一个文件系统,并且mount可以挂载多次。每次实列化的时候,都生成一个,就是类的成员变量。不是静态变量。mount的时候生成super_block.

sb(超级块)管理多个inode, 必须要有inode,才可以存贮数据,具体存贮数据的地方,数据的组织。

new_inode源码 填充super_block

linux  0.1.1    __syscall0  跑在用户空间的  unistd.h

open  -->sys_open  如何做的?

fn_ptr  sys_call_table[]  

所有的系统调用 sys.h

sys_call_table +NR_fork *4(指针4个字节) :找到系统调用。。  系统调用都是0x80的软中断 

系统调用过程

https://www.1024sou.com/article/363306.html  netlink 协议栈实战

一、libnet库下载:

官网下载地址:

https://github.com/sam-github/libnet

http://sourceforge.net/projects/libnet-dev/

http://packetfactory.openwall.net/projects/libnet/index.html

二、libnet库编译:

CSDN博客上的编译:

http://blog.csdn.net/kanguolaikanguolaik/article/details/9358665

三、libnet库简单示例:

官网示例代码:

http://packetfactory.openwall.net/projects/libnet/dist/deprecated/manual/index.html

四、libnet文档:

官网文档:

http://packetfactory.openwall.net/projects/libnet/dist/deprecated/manual/index.html

三、虚拟文件系统VFS的实现原理

proc: 内核进程信息导入到用户空间,后来是内核信息导入到用户空间

sockfs  proc sysfs cgroup  伪文件系统(假的文件系统)

四、用户态文件系统fuse   、/dev/fuse

操作系统的文件系统与分布式文件系统的区别

1. 操作系统的文件系统是根据磁盘做索引的,一块一块的存储,分布式文件系统是基于操作系统的文件系统做的,并且是基于文件本身做索引的

libfuse, 是对/dev/fuse,open  read write的一系列的操作的封装  等待更新。。。。

五、虚拟网络适配器的实现

什么是服务器?

(1) 服务器物理硬件laaS (2) 操作系统 服务器版本PaaS  3应用程序 SaaS

服务器为什么能响应网络,网卡

网卡的作用:AD/DA转换

eth0/eth1/eth2: 网络适配器,适配现有绝大多数网卡 ,软件代码适配

网络适配器如何去适配所有的网卡?

1.属性   2.方法            面向对象

net_device实列化一次,就会有一个网络适配器

ifconfig 显示的内容都会存储再struct net_device的对象里

net_device_ops

上一篇 下一篇

猜你喜欢

热点阅读