![](https://img-blog.csdnimg.cn/20201014180756930.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
Linux操作系统
文章平均质量分 93
Linux操作系统
_Rye_
左手代码右手诗
一行代码一行诗
展开
-
面试题 | 操作系统问题
长发哥:这个程序运行时间一长就挂了,咋回事呀?秃头哥:这不有异常吗?超过最大打开文件数了。长发哥:打开文件还有限制?秃头哥:……原创 2024-01-28 15:22:21 · 364 阅读 · 0 评论 -
66 | 知识串讲:用一个创业故事串起操作系统原理(五)
上一节我们说到,马哥的公司现在接个千万级别的项目没有任何问题,但是投资人说,要想冲一把上市,还差点劲,目前的项目虽然大,但是想象力不够丰富。原创 2024-01-27 22:47:17 · 813 阅读 · 0 评论 -
65 | 知识串讲:用一个创业故事串起操作系统原理(四)
上一节,小马的公司已经解决了生存问题,成功从小马晋升马哥。马哥是一个有危机意识的人。尽管公司开始不断盈利,项目像流水一样,一个接一个,赚了点儿钱,但是他感觉还是有点儿像狗熊掰棒子。因为公司没有积累,永远就都是在做小生意,无法实现成倍的增长。马哥想,公司做了这么多的项目,应该有很多的共同点,能积累下来非常多的资料。如果能够把这些资料归档、总结、积累,形成核心竞争力,就可以随着行业的飞跃,深耕一个行业,实现快速增长。原创 2024-01-27 18:53:03 · 845 阅读 · 0 评论 -
64 | 知识串讲:用一个创业故事串起操作系统原理(三)
上一节我们说到,周瑜和张昭商定了调用 schedule 的时机。尽管项目越来越多,但是也井井有条。可是我们也说了,不管你的事情做得有多好,项目保密问题都是要解决的重要问题。怎么解决呢?今天我们就来看一看。原创 2024-01-27 13:41:01 · 915 阅读 · 0 评论 -
63 | 知识串讲:用一个创业故事串起操作系统原理(二)
上一节说到小马同学的公司已经创立了,还请来了周瑜和张昭作为帮手,所谓“兄弟齐心,其利断金”。可是,现在这家公司,还得从接第一个外部项目开始。原创 2024-01-27 13:10:02 · 966 阅读 · 0 评论 -
62 | 知识串讲:用一个创业故事串起操作系统原理(一)
操作系统是一门体系复杂、知识点很多的课程,经过这么多节的讲解,你是否已经感觉自己被淹没在细节的汪洋大海里面了?没关系,从这一节开始,我们用五节的时间,通过一个创业故事,串起来操作系统的整个知识体系。接下来,我们就来看主人公是如何从小马,变成马哥,再变成马总的吧!原创 2024-01-26 22:32:13 · 864 阅读 · 0 评论 -
61 | 搭建操作系统实验环境(下):授人以鱼不如授人以渔
在这个课程里面,我们写过一些程序,为了保证程序能够顺利运行,一般会将代码完整地放到文本中,让你拷贝下来就能编译和运行。如果运行的时候发现有问题,或者想了解一步一步运行的细节,这一节介绍的 gdb 是一个很好的工具。这一节尤其应该掌握的是,如何通过宿主机上的 gdb 来 debug 虚拟机里面的内核。这一点非常重要,会了这个,你就能够返回去,挨个研究每一章每一节的内核数据结构和运行逻辑了。在这门课中,进程管理、内存管理、文件管理、设备管理网络管理,我们都介绍了从系统调用到底层的整个逻辑。原创 2024-01-26 20:34:37 · 780 阅读 · 0 评论 -
60 | 搭建操作系统实验环境(上):授人以鱼不如授人以渔
这一节是一节实战课,我们创建了一台虚拟机,在里面下载源代码,尝试修改了 Linux 内核,添加了一个自己的系统调用,并且进行了编译并安装了新内核。如果你按照这个过程做下来,你会惊喜地发现,原来令我们敬畏的内核,也是能够加以干预,为我而用的呢。没错,这就是开始逐渐掌握内核的重要一步。原创 2024-01-26 19:04:19 · 771 阅读 · 0 评论 -
59 | 数据中心操作系统:上市敲钟
下面,你可以对照着这个图,来总结一下这个数据中心操作系统的功能。原创 2024-01-26 18:30:15 · 691 阅读 · 0 评论 -
58 | cgroup技术:内部创业公司应该独立核算成本
内核中 cgroup 的工作机制,我们在这里总结一下。第一步,系统初始化的时候,初始化 cgroup 的各个子系统的操作函数,分配各个子系统的数据结构。第二步,mount cgroup 文件系统,创建文件系统的树形结构,以及操作函数。第三步,写入 cgroup 文件,设置 cpu 或者 memory 的相关参数,这个时候文件系统的操作函数会调用到 cgroup 子系统的操作函数,从而将参数设置到 cgroup 子系统的数据结构中。原创 2024-01-26 17:48:42 · 845 阅读 · 0 评论 -
57 | Namespace技术:内部创业公司应该独立运营
这一节我们讲了 namespace 相关的技术,有六种类型,分别是 UTS、User、Mount、Pid、Network 和 IPC。还有两个常用的命令 nsenter 和 unshare,主要用于操作 Namespace,有三个常用的函数 clone、setns 和 unshare。原创 2024-01-26 16:21:55 · 819 阅读 · 0 评论 -
56 | 容器:大公司为保持创新,鼓励内部创业
这里我们来总结一下这一节的内容。无论是容器,还是虚拟机,都依赖于内核中的技术,虚拟机依赖的是 KVM,容器依赖的是 namespace 和 cgroup 对进程进行隔离。为了运行 Docker,有一个 daemon 进程 Docker Daemon 用于接收命令行。为了描述 Docker 里面运行的环境和应用,有一个 Dockerfile,通过 build 命令称为容器镜像。容器镜像可以上传到镜像仓库,也可以通过 pull 命令从镜像仓库中下载现成的容器镜像。原创 2024-01-26 15:35:38 · 353 阅读 · 0 评论 -
55 | 网络虚拟化:如何成立独立的合作部?
最后,我们把网络虚拟化场景下网络包的发送过程总结一下。在虚拟机里面的用户态,应用程序通过 write 系统调用写入 socket。写入的内容经过 VFS 层,内核协议栈,到达虚拟机里面的内核的网络设备驱动,也即 virtio_net。virtio_net 网络设备有一个操作结构 struct net_device_ops,里面定义了发送一个网络包调用的函数为 start_xmit。原创 2024-01-26 14:37:07 · 866 阅读 · 0 评论 -
54 | 存储虚拟化(下):如何建立自己保管的单独档案库?
下面我们来总结一下存储虚拟化的场景下,整个写入的过程。在虚拟机里面,应用层调用 write 系统调用写入文件。write 系统调用进入虚拟机里面的内核,经过 VFS,通用块设备层,I/O 调度层,到达块设备驱动。虚拟机里面的块设备驱动是 virtio_blk,它和通用的块设备驱动一样,有一个 request queue,另外有一个函数 make_request_fn 会被设置为 blk_mq_make_request,这个函数用于将请求放入队列。原创 2024-01-26 11:25:01 · 856 阅读 · 0 评论 -
53 | 存储虚拟化(上):如何建立自己保管的单独档案库?
我们这里来总结一下,存储虚拟化的过程分为前端、后端和中间的队列。前端有前端的块设备驱动 Front-end driver,在客户机的内核里面,它符合普通设备驱动的格式,对外通过 VFS 暴露文件系统接口给客户机里面的应用。这一部分这一节我们没有讲,放在下一节解析。后端有后端的设备驱动 Back-end driver,在宿主机的 qemu 进程中,当收到客户机的写入请求的时候,调用文件系统的 write 函数,写入宿主机的 VFS 文件系统,最终写到物理硬盘设备上的 qcow2 文件。原创 2024-01-26 10:30:52 · 901 阅读 · 0 评论 -
52 | 计算虚拟化之内存:如何建立独立的办公室?
我们这里来总结一下,虚拟机的内存管理也是需要用户态的 qemu 和内核态的 KVM 共同完成。为了加速内存映射,需要借助硬件的 EPT 技术。在用户态 qemu 中,有一个结构 AddressSpace address_space_memory 来表示虚拟机的系统内存,这个内存可能包含多个内存区域 struct MemoryRegion,组成树形结构,指向由 mmap 分配的虚拟内存。原创 2024-01-26 09:25:23 · 891 阅读 · 0 评论 -
51 | 计算虚拟化之CPU(下):如何复用集团的人力资源?
CPU 的虚拟化过程还是很复杂的,画了一张图总结了一下。首先,我们要定义 CPU 这种类型的 TypeInfo 和 TypeImpl、继承关系,并且声明它的类初始化函数。在 qemu 的 main 函数中调用 MachineClass 的 init 函数,这个函数既会初始化 CPU,也会初始化内存。CPU 初始化的时候,会调用 pc_new_cpu 创建一个虚拟 CPU,它会调用 CPU 这个类的初始化函数。原创 2024-01-25 17:10:39 · 873 阅读 · 0 评论 -
50 | 计算虚拟化之CPU(上):如何复用集团的人力资源?
这一节,我们学到,虚拟机对于设备的模拟是一件非常复杂的事情,需要用复杂的参数模拟各种各样的设备。为了能够适配这些设备,qemu 定义了自己的模块管理机制,只有了解了这种机制,后面看每一种设备的虚拟化的时候,才有一个整体的思路。这里的 MachineClass 是我们遇到的第一个,需要掌握它里面各种定义之间的关系。每个模块都会有一个定义 TypeInfo,会通过 type_init 变为全局的 TypeImpl。TypeInfo 以及生成的 TypeImpl 有以下成员:name 表示当前类型的名称。原创 2024-01-25 16:31:15 · 1010 阅读 · 0 评论 -
49 | 虚拟机:如何成立子公司,让公司变集团?
今天讲了虚拟化的基本原理,并且手动创建一个可以上网的虚拟机。请记住下面这一点,非常重要,理解虚拟机启动的参数就是理解虚拟化技术的入口。学会创建虚拟机,在后面做内核相关实验的时候就会非常方便。具体到知识点上,这一节需要需要记住下面的这些知识点:虚拟化的本质是用 qemu 的软件模拟硬件,但是模拟方式比较慢,需要加速;虚拟化主要模拟 CPU、内存、网络、存储,分别有不同的加速办法;CPU 和内存主要使用硬件辅助虚拟化进行加速,需要配备特殊的硬件才能工作;原创 2024-01-25 15:48:25 · 919 阅读 · 0 评论 -
48 | 接收网络包(下):如何搞明白合作伙伴让我们做什么?
这一节讲完了接收网络包,来从头串一下,整个过程可以分成以下几个层次。硬件网卡接收到网络包之后,通过 DMA 技术,将网络包放入 Ring Buffer;硬件网卡通过中断通知 CPU 新的网络包的到来;网卡驱动程序会注册中断处理函数 ixgb_intr;中断处理函数处理完需要暂时屏蔽中断的核心流程之后,通过软中断 NET_RX_SOFTIRQ 触发接下来的处理过程;原创 2023-10-05 15:52:57 · 47 阅读 · 0 评论 -
47 | 接收网络包(上):如何搞明白合作伙伴让我们做什么?
这一节讲了接收网络包的上半部分,分以下几个层次。硬件网卡接收到网络包之后,通过 DMA 技术,将网络包放入 Ring Buffer。硬件网卡通过中断通知 CPU 新的网络包的到来。网卡驱动程序会注册中断处理函数 ixgb_intr。中断处理函数处理完需要暂时屏蔽中断的核心流程之后,通过软中断 NET_RX_SOFTIRQ 触发接下来的处理过程。原创 2023-10-04 15:52:24 · 78 阅读 · 0 评论 -
46 | 发送网络包(下):如何表达我们想让合作伙伴做什么?
这一节,继续解析了发送一个网络包的过程,整个过程的图画在了下面。这个过程分成几个层次。VFS 层:write 系统调用找到 struct file,根据里面的 file_operations 的定义,调用 sock_write_iter 函数。sock_write_iter 函数调用 sock_sendmsg 函数。Socket 层:从 struct file 里面的 private_data 得到 struct socket,根据里面 ops 的定义,调用 inet_sendmsg 函数。原创 2023-10-02 12:39:40 · 71 阅读 · 0 评论 -
45 | 发送网络包(上):如何表达我们想让合作伙伴做什么?
这一节,解析了发送一个网络包的一部分过程,如下图所示。这个过程分成几个层次。VFS 层:write 系统调用找到 struct file,根据里面的 file_operations 的定义,调用 sock_write_iter 函数。sock_write_iter 函数调用 sock_sendmsg 函数。Socket 层:从 struct file 里面的 private_data 得到 struct socket,根据里面 ops 的定义,调用 inet_sendmsg 函数。原创 2023-10-02 00:37:11 · 26 阅读 · 0 评论 -
44 | Socket内核数据结构:如何成立特大项目合作部?
这一节除了网络包的接收和发送,其他的系统调用都分析到了。可以看出来,它们有一个统一的数据结构和流程。具体如下图所示:首先,Socket 系统调用会有三级参数 family、type、protocal,通过这三级参数,分别在 net_proto_family 表中找到 type 链表,在 type 链表中找到 protocal 对应的操作。这个操作分为两层,对于 TCP 协议来讲,第一层是 inet_stream_ops 层,第二层是 tcp_prot 层。原创 2023-10-01 20:06:36 · 31 阅读 · 0 评论 -
43 | Socket通信:遇上特大项目,要学会和其他公司合作
这一节讲了网络协议的基本原理和 socket 系统调用,这里重点关注 TCP 协议的系统调用。通过学习,我们知道,socket 系统调用是用户态和内核态的接口,网络协议的四层以下都是在内核中的。很多的书籍会讲如何开发一个高性能的 socket 程序,但是这不是我们这门课的重点,所以我们主要看内核里面的机制就行了。因此,需要记住 TCP 协议的 socket 调用的过程。接下来就按照这个顺序,依次回忆一下这些系统调用到内核都做了什么:服务端和客户端都调用 socket,得到文件描述符;原创 2023-10-01 19:54:15 · 71 阅读 · 0 评论 -
43 Socket通信之网络协议基本原理
网络协议是一个大话题,这个专栏重点解析在这个网络通信过程中,发送端和接收端的操作系统都做了哪些事情,对于中间通路上的复杂的网络通信逻辑没有做深入解析。如果只是为了掌握这一章的内容,只要记住 TCP/UDP->IPv4->ARP 这一条链就可以了,因为后面的分析都是重点分析这条链。原创 2023-10-01 15:28:06 · 402 阅读 · 0 评论 -
42 | IPC(下):不同项目组之间抢资源,如何协调?
信号量的机制也很复杂,对着下面这个图总结一下。1. 调用 semget 创建信号量集合。2. ipc_findkey 会在基数树中,根据 key 查找信号量集合 sem_array 对象。如果已经被创建,就会被查询出来。例如 producer 被创建过,在 consumer 中就会查询出来。3. 如果信号量集合没有被创建过,则调用 sem_ops 的 newary 方法,创建一个信号量集合对象 sem_array。例如,在 producer 中就会新建。原创 2023-10-01 15:00:29 · 38 阅读 · 0 评论 -
41 | IPC(中):不同项目组之间抢资源,如何协调?
总结一下共享内存的创建和映射过程。1. 调用 shmget 创建共享内存。2. 先通过 ipc_findkey 在基数树中查找 key 对应的共享内存对象 shmid_kernel 是否已经被创建过,如果已经被创建,就会被查询出来,例如 producer 创建过,在 consumer 中就会查询出来。3. 如果共享内存没有被创建过,则调用 shm_ops 的 newseg 方法,创建一个共享内存对象 shmid_kernel。例如,在 producer 中就会新建。原创 2023-10-01 13:55:54 · 48 阅读 · 0 评论 -
40 | IPC(上):不同项目组之间抢资源,如何协调?
这一节的内容差不多了,我们来总结一下。共享内存和信号量的配合机制,如下图所示:无论是共享内存还是信号量,创建与初始化都遵循同样流程,通过 ftok 得到 key,通过 xxxget 创建对象并生成 id;生产者和消费者都通过 shmat 将共享内存映射到各自的内存空间,在不同的进程里面映射的位置不同;为了访问共享内存,需要信号量进行保护,信号量需要通过 semctl 初始化为某个值;原创 2023-10-01 13:36:18 · 44 阅读 · 0 评论 -
39 | 管道:项目组A完成了,如何交接给项目组B?
无论是匿名管道,还是命名管道,在内核都是一个文件。只要是文件就要有一个 inode。这里我们又用到了特殊 inode、字符设备、块设备,其实都是这种特殊的 inode。在这种特殊的 inode 里面,file_operations 指向管道特殊的 pipefifo_fops,这个 inode 对应内存里面的缓存。原创 2023-10-01 13:11:01 · 30 阅读 · 0 评论 -
38 | 信号(下):项目组A完成了,如何及时通知项目组B?
信号的发送与处理是一个复杂的过程,这里来总结一下。1. 假设我们有一个进程 A,main 函数里面调用系统调用进入内核。2. 按照系统调用的原理,会将用户态栈的信息保存在 pt_regs 里面,也即记住原来用户态是运行到了 line A 的地方。3. 在内核中执行系统调用读取数据。4. 当发现没有什么数据可读取的时候,只好进入睡眠状态,并且调用 schedule 让出 CPU,这是进程调度第一定律。原创 2023-10-01 01:18:17 · 43 阅读 · 0 评论 -
37 | 信号(上):项目组A完成了,如何及时通知项目组B?
这一节讲了如何通过 API 注册一个信号处理函数,整个过程如下图所示。在用户程序里面,有两个函数可以调用,一个是 signal,一个是 sigaction,推荐使用 sigaction。用户程序调用的是 Glibc 里面的函数,signal 调用的是 __sysv_signal,里面默认设置了一些参数,使得 signal 的功能受到了限制,sigaction 调用的是 __sigaction,参数用户可以任意设定。原创 2023-10-01 00:45:41 · 37 阅读 · 0 评论 -
36 | 进程间通信:遇到大项目需要项目组之间的合作才行
这一节,整体讲解了一下进程间通信的各种模式。类似瀑布开发模式的管道类似邮件模式的消息队列类似会议室联合开发的共享内存加信号量类似应急预案的信号当你自己使用的时候,可以根据不同的通信需要,选择不同的模式。管道,这是命令行中常用的模式,面试问到的话,不要忘了。消息队列其实很少使用,因为有太多的用户级别的消息队列,功能更强大。共享内存加信号量是常用的模式。这个需要牢记,常见到一些知名的以 C 语言开发的开源软件都会用到它。信号更加常用,机制也比较复杂。后面会有单独的一节来解析。原创 2023-10-01 00:31:45 · 53 阅读 · 0 评论 -
35 | 块设备(下):如何建立代理商销售模式?
这一节讲了如何将块设备 I/O 请求送达到外部设备。对于块设备的 I/O 操作分为两种,一种是直接 I/O,另一种是缓存 I/O。无论是哪种 I/O,最终都会调用 submit_bio 提交块设备 I/O 请求。对于每一种块设备,都有一个 gendisk 表示这个设备,它有一个请求队列,这个队列是一系列的 request 对象。每个 request 对象里面包含多个 BIO 对象,指向 page cache。所谓的写入块设备,I/O 就是将 page cache 里面的数据写入硬盘。原创 2023-10-01 00:18:11 · 84 阅读 · 0 评论 -
34 | 块设备(上):如何建立代理商销售模式?
从这一节可以看出,块设备比字符设备复杂多了,涉及三个文件系统,工作过程用一张图总结了一下。1. 所有的块设备被一个 map 结构管理从 dev_t 到 gendisk 的映射;2. 所有的 block_device 表示的设备或者分区都在 bdev 文件系统的 inode 列表中;3. mknod 创建出来的块设备文件在 devtemfs 文件系统里面,特殊 inode 里面有块设备号;4. mount 一个块设备上的文件系统,调用这个文件系统的 mount 接口;原创 2023-10-01 00:12:25 · 76 阅读 · 0 评论 -
33 | 字符设备(下):如何建立直销模式?
这一节,讲了中断的整个处理过程。中断是从外部设备发起的,会形成外部中断。外部中断会到达中断控制器,中断控制器会发送中断向量 Interrupt Vector 给 CPU。对于每一个 CPU,都要求有一个 idt_table,里面存放了不同的中断向量的处理函数。中断向量表中已经填好了前 32 位,外加一位 32 位系统调用,其他的都是用于设备中断。硬件中断的处理函数是 do_IRQ 进行统一处理,在这里会让中断向量,通过 vector_irq 映射为 irq_desc。原创 2023-09-30 20:32:01 · 34 阅读 · 0 评论 -
32 | 字符设备(上):如何建立直销模式?
这一节讲了字符设备的打开、写入和 ioctl 等最常见的操作。一个字符设备要能够工作,需要三部分配合。第一,有一个设备驱动程序的 ko 模块,里面有模块初始化函数、中断处理函数、设备操作函数。这里面封装了对于外部设备的操作。加载设备驱动程序模块的时候,模块初始化函数会被调用。在内核维护所有字符设备驱动的数据结构 cdev_map 里面注册,我们就可以很容易根据设备号,找到相应的设备驱动程序。原创 2023-09-30 12:01:50 · 30 阅读 · 0 评论 -
31 | 输入与输出:如何建立售前售后生态体系?
这一节,讲了输入与输出设备的管理,内容比较多。输入输出设备就像管理代理商一样。因为代理商复杂多变,代理商管理也同样复杂多变,需要层层屏蔽差异化的部分,给上层提供标准化的部分,最终到用户态,给用户提供了基于文件系统的统一的接口。原创 2023-09-30 10:56:32 · 99 阅读 · 0 评论 -
30 | 文件缓存:常用文档应该放在触手可得的地方
这一节对于读取和写入的分析就到这里了。这个过程还是很复杂的,这里画了一张调用图,可以看到调用过程。在系统调用层需要仔细学习 read 和 write。在 VFS 层调用的是 vfs_read 和 vfs_write 并且调用 file_operation。在 ext4 层调用的是 ext4_file_read_iter 和 ext4_file_write_iter。接下来就是分叉。需要知道缓存 I/O 和直接 I/O。原创 2023-09-30 05:15:58 · 82 阅读 · 0 评论 -
29 | 虚拟文件系统:文件多了就需要档案管理系统
对于虚拟文件系统的解析就到这里了,可以看出,有关文件的数据结构层次多,而且很复杂,就得到了下面这张图,这张图在最开始的时候,已经展示过一遍,到这里,应该能明白它们之间的关系了。这张图十分重要,因为后面的字符设备、块设备、管道、进程间通信、网络等等,全部都要用到这里面的知识。希望再次遇到它的时候,能够马上说出各个数据结构之间的关系。这里简单做一个梳理,帮助理解记忆它。对于每一个进程,打开的文件都有一个文件描述符,在 files_struct 里面会有文件描述符数组。原创 2023-09-30 04:58:53 · 47 阅读 · 0 评论