目录

Linux 系统原理

单内核设计:内核从整体上作为一个单独的大过程来实现,运行在一个单独的地址空间上,内核以单个二进制文件的形式存放于磁盘中.因为所有内核服务都在这样一个大内核地址空间上运行,所以通信可以直接调用函数来实现。linux 就是一个单内核设计。

本文记录的是我学习到的Linux本身的一些原理性的知识,它的构成与实现。

image-20210320185347876

进程管理

负责创建、结束进程,管理内核的活动,如软件中断、tasklet等,管理进程间通信,如消息(message)、管道(pipe)等,实现进程调度(schedule)。进程调度是进程管理的重要任务,它处理所有活动的、等待被执行的和被阻塞(blocking)的进程调度,使所有应用和进程合理地共享处理器的运行时间。

内存管理

内存是系统最主要的资源之一,计算机的性能在很大程度上与其所配备的内存有关。Linux内核内存管理的主要功能就是给进程分配地址空间,该地址空间只允许本进程自己访问。

文件系统

在Linux操作系统中,文件系统是整个系统的中枢。Linux与其他操作系统不同,几乎所有的操作都基于文件系统接口的处理,如设备驱动程序可以按文件方式访问设备,通过/proc文件系统可以访问Linux内核的数据和参数,这两个功能在调试时非常有效。

设备驱动程序

在所有的操作系统中,设备驱动程序都是硬件的抽象,通过它可以访问硬件。Linux可以用模块(模块)的方式实现设备驱动程序,提供了在系统运行时动态加载和卸载设备驱动程序的途径。

网络子系统

在Linux中所有的网络操作是由操作系统管理的。这是因为网络操作不能分配给某个进程完成。在处理收到的网络数据包时,数据包的接收是异步事件。接收数据包任务必须在进程处理这些数据包前先收集齐所有的网络包、标识数据,然后向上层传送,这就是为什么由内核的网络子系统负责处理数据包,而不是由某个进程和网络接口来处理。

内核用于所有 I/O 的数据结构

每个进程都有一张 打开文件描述符表,该表的每一条记录的结构为:

  1. 文件描述符标志 close_on_exec

  2. 指向一个文件表项的指针

内核为所有打开文件维持一张文件表,每个记录包含:

  1. 文件状态标志

  2. 当前文件偏移量

  3. 指向该文件 v 节点表的指针

每个打开文件/设备都有一个v-node结构,这个结构的内容有:

  1. 文件类型

  2. 对此文件进行各种操作的函数的指针

  3. 该文件的 i 节点, i 节点内部包含了文件所有者,文件长度,指向文件实际数据块在磁盘上所在位置的指针等

WX20181204-162658.png

两个进程打开同一个文件

WX20181204-162945.png

打开该文件的每个进程都获得各自的一个文件表项,但对于一个给定的文件只有唯一的一个v节点表项

  • 现在对 I/O 操作进行一个说明

    • 在完成每个 write 后,文件表项中的 cur_file_offset 立即增加所写入的字节数,如果该偏移量的值超过文件长度,则 i 节点表项中的当前文件长度设置为偏移量的长度,也就是文件加长了

    • 以 O_APPEND 标志打开文件,该标志被设置到文件表项的文件状态标志中,每次进行写入时,文件表项中的cur_file_offset 会被设置为当前文章长度。这就使得每次写入数据都是追加到文件末尾的

    • 一个文件用 lseek 定位到文件尾端,对应的数据结构的修改就是,文件表项中的 cur_file_offset 被设置为当前文件长度,lseek 只修改当前文件偏移量,不进行任何 io 操作

    • 多个文件描述符可以指向同一个文件表项,dup 函数可以实现;fork 后也会出现这种情况,此时父进程、子进程各自的那个文件描述符共享同一个文件表项

文件类型

  • 普通文件,包括纯文本文件以及二进制文件,在内核看了它们 没有区别,读出来都是字节流

  • 目录文件 directory file,包含其他文件的名字,以及指向这些文件有关信息的指针

  • 块特殊文件 block special file,提供对设备(磁盘)带缓冲的访问,每次访问  以固定长度为单位进行

  • 字符特殊文件 character special file 提供  对设备不带缓冲的访问,每次访问长度可变,系统中的设备要么是块特殊文件,要么是字符特殊文件

  • FIFO 命名管道 用于进程间通信

  • socket 套接字 用于进程间的网络通信,也可用在一台主机上进程  之间的通信

  • 符号链接 symbolic link 这种文件指向另一个文件

一个进程关联的 ID

  • 当前进程的实际用户是谁

    • 实际用户 ID

    • 实际组 ID

  • 用于文件访问权限检查

    • 有效用户 ID

    • 有效组 ID

    • 附属组 ID

  • 由 exec 函数保存,是有效用户 ID 与有效组 ID 的副本

    • 保存的设置用户 ID

    • 保存的设置组 ID

文件系统

  • 一块磁盘分成多个分区,每一个分区可以包含一个文件系统

WX20181205-150455.png

  • 两个目录块中的项指向同一个 i 节点,每个 i 节点都有一个链接计数,它减到 0 时,文件才被删除

  • 符号链接的文件类型是 S_IFLNK, 内核知道这是一个符号链接

  • i 节点包含了文件有关的所有信息:文件类型,文件访问权限位,文件长度,指向文件数据块的指针集合等

WX20181205-150747.png

  • 创建新目录 testdir 之后,文件系统结构的生成与变化

WX20181205-151559.png

符号链接

  • 硬链接要求链接与文件位于同一文件系统中

  • 只有超级用户才能创建指向目录的硬链接

标准 IO

  • 流 stream 标准 IO 库打开一个文件时,这个流与这个文件相关联

  • ASCII 字符集,一个字符使用一个字节存储,国际字符集,一个字符用  多个字节存储

  • 流的定向 stream orientation决定了读写字符是使用单字节模式,还是多字节模式

  • fopen返回一个FILE指针,这个指针包含了管理该文件对应的流的所有信息(文件描述符,指向缓冲区的指针,缓冲区的长度,当前在缓冲区中的字符数以及出错标志)

  • strin stdout stderr三个标准流

标准 IO 带来的缓冲

  • 全缓冲:填满 IO 缓冲区后,才进行实际的 I/O 操作

  • 行缓冲:在输入和输出中遇到换行符时,标准 IO 库执行 IO 操作,有两个限制如下

    1. 缓冲区被填满,不管有没有遇到换行符,都执行实际的 IO 操作

    2. 任何时候,只要通过标准 IO 库从 (a)不带缓冲的流 (b)行缓冲的流 中读取数据时,就会先输出输出流的缓冲数据

  • 不带缓冲:标准 I/O 库不对字符进程缓冲存储,例如fputs函数,stderr流设置为不带缓冲的

KVM

KVM 集成在内核中,是内核的一个模块

# 查看是否支持 KVM 返回不等于0,则支持
$ egrep -c "(svm|vmx)" /proc/cpuinfo

# 安装 KVM
$ sudo aptitude install -y qemu-kvm qemu virt-manager virt-viewer libvirt-bin bridge-utils

# 验证kvm是否安装正确
$ lsmod |grep kvm
kvm_intel             200704  0
kvm                   593920  1 kvm_intel
irqbypass              16384  1 kvm