第1章 简介和概述 1
1.1 内核的任务 2
1.2 实现策略 2
1.3 内核的组成部分 3
1.3.1 进程、进程切换、调度 3
1.3.2 UNIX进程 4
1.3.3 地址空间与特权级别 6
1.3.4 页表 9
1.3.5 物理内存的分配 11
1.3.6 计时 13
1.3.7 系统调用 13
1.3.8 设备驱动程序、块设备和字符设备 14
1.3.9 网络 14
1.3.10 文件系统 14
1.3.11 模块和热插拔 15
1.3.12 缓存 16
1.3.13 链表处理 16
1.3.14 对象管理和引用计数 17
1.3.15 数据类型 20
1.3.16 本书的局限性 22
1.4 为什么内核是特别的 23
1.5 行文注记 23
1.6 小结 27
第2章 进程管理和调度 28
2.1 进程优先级 28
2.2 进程生命周期 30
2.3 进程表示 32
2.3.1 进程类型 37
2.3.2 命名空间 37
2.3.3 进程ID号 43
2.3.4 进程关系 49
2.4 进程管理相关的系统调用 50
2.4.1 进程复制 50
2.4.2 内核线程 62
2.4.3 启动新程序 63
2.4.4 退出进程 66
2.5 调度器的实现 67
2.5.1 概观 67
2.5.2 数据结构 69
2.5.3 处理优先级 74
2.5.4 核心调度器 79
2.6 完全公平调度类 84
2.6.1 数据结构 85
2.6.2 CFS操作 85
2.6.3 队列操作 89
2.6.4 选择下一个进程 91
2.6.5 处理周期性调度器 92
2.6.6 唤醒抢占 93
2.6.7 处理新进程 93
2.7 实时调度类 94
2.7.1 性质 94
2.7.2 数据结构 95
2.7.3 调度器操作 96
2.8 调度器增强 97
2.8.1 SMP调度 97
2.8.2 调度域和控制组 101
2.8.3 内核抢占和低延迟相关工作 102
2.9 小结 106
第3章 内存管理 107
3.1 概述 107
3.2 (N)UMA模型中的内存组织 109
3.2.1 概述 109
3.2.2 数据结构 111
3.3 页表 123
3.3.1 数据结构 124
3.3.2 页表项的创建和操作 129
3.4 初始化内存管理 129
3.4.1 建立数据结构 130
3.4.2 特定于体系结构的设置 135
3.4.3 启动过程期间的内存管理 153
3.5 物理内存的管理 159
3.5.1 伙伴系统的结构 159
3.5.2 避免碎片 161
3.5.3 初始化内存域和结点数据结构 167
3.5.4 分配器API 172
3.5.5 分配页 177
3.5.6 释放页 192
3.5.7 内核中不连续页的分配 195
3.5.8 内核映射 201
3.6 slab分配器 205
3.6.1 备选分配器 206
3.6.2 内核中的内存管理 207
3.6.3 slab分配的原理 209
3.6.4 实现 212
3.6.5 通用缓存 226
3.7 处理器高速缓存和TLB控制 228
3.8 小结 230
第4章 进程虚拟内存 231
4.1 简介 231
4.2 进程虚拟地址空间 231
4.2.1 进程地址空间的布局 232
4.2.2 建立布局 234
4.3 内存映射的原理 237
4.4 数据结构 238
4.4.1 树和链表 238
4.4.2 虚拟内存区域的表示 239
4.4.3 优先查找树 241
4.5 对区域的操作 244
4.5.1 将虚拟地址关联到区域 245
4.5.2 区域合并 246
4.5.3 插入区域 247
4.5.4 创建区域 248
4.6 地址空间 250
4.7 内存映射 251
4.7.1 创建映射 251
4.7.2 删除映射 253
4.7.3 非线性映射 254
4.8 反向映射 257
4.8.1 数据结构 258
4.8.2 建立逆向映射 259
4.8.3 使用逆向映射 259
4.9 堆的管理 261
4.10 缺页异常的处理 263
4.11 用户空间缺页异常的校正 268
4.11.1 按需分配/调页 269
4.11.2 匿名页 271
4.11.3 写时复制 271
4.11.4 获取非线性映射 272
4.12 内核缺页异常 272
4.13 在内核和用户空间之间复制数据 274
4.14 小结 276
第5章 锁与进程间通信 277
5.1 控制机制 277
5.1.1 竞态条件 277
5.1.2 临界区 278
5.2 内核锁机制 279
5.2.1 对整数的原子操作 280
5.2.2 自旋锁 282
5.2.3 信号量 283
5.2.4 RCU机制 284
5.2.5 内存和优化屏障 286
5.2.6 读者/写者锁 287
5.2.7 大内核锁 288
5.2.8 互斥量 288
5.2.9 近似的per-CPU计数器 290
5.2.10 锁竞争与细粒度锁 291
5.3 System V进程间通信 292
5.3.1 System V机制 292
5.3.2 信号量 292
5.3.3 消息队列 300
5.3.4 共享内存 303
5.4 其他IPC机制 303
5.4.1 信号 303
5.4.2 管道和套接字 310
5.5 小结 311
第6章 设备驱动程序 312
6.1 I/O体系结构 312
6.2 访问设备 316
6.2.1 设备文件 316
6.2.2 字符设备、块设备和其他设备 317
6.2.3 使用ioctl进行设备寻址 319
6.2.4 主从设备号的表示 320
6.2.5 注册 321
6.3 与文件系统关联 324
6.3.1 inode中的设备文件成员 324
6.3.2 标准文件操作 325
6.3.3 用于字符设备的标准操作 325
6.3.4 用于块设备的标准操作 325
6.4 字符设备操作 326
6.4.1 表示字符设备 326
6.4.2 打开设备文件 326
6.4.3 读写操作 328
6.5 块设备操作 329
6.5.1 块设备的表示 330
6.5.2 数据结构 331
6.5.3 向系统添加磁盘和分区 338
6.5.4 打开块设备文件 339
6.5.5 请求结构 341
6.5.6 BIO 343
6.5.7 提交请求 345
6.5.8 I/O调度 350
6.5.9 ioctl的实现 352
6.6 资源分配 353
6.6.1 资源管理 353
6.6.2 I/O内存 355
6.6.3 I/O端口 357
6.7 总线系统 358
6.7.1 通用驱动程序模型 358
6.7.2 PCI总线 363
6.7.3 USB 370
6.8 小结 376
第7章 模块 377
7.1 概述 377
7.2 使用模块 378
7.2.1 添加和移除 378
7.2.2 依赖关系 380
7.2.3 查询模块信息 381
7.2.4 自动加载 382
7.3 插入和删除模块 384
7.3.1 模块的表示 385
7.3.2 依赖关系和引用 389
7.3.3 模块的二进制结构 391
7.3.4 插入模块 396
7.3.5 移除模块 403
7.4 自动化与热插拔 404
7.4.1 kmod实现的自动加载 404
7.4.2 热插拔 405
7.5 版本控制 408
7.5.1 校验和方法 408
7.5.2 版本控制函数 411
7.6 小结 412
第8章 虚拟文件系统 413
8.1 文件系统类型 413
8.2 通用文件模型 414
8.2.1 inode 415
8.2.2 链接 416
8.2.3 编程接口 416
8.2.4 将文件作为通用接口 417
8.3 VFS的结构 417
8.3.1 结构概观 418
8.3.2 inode 419
8.3.3 特定于进程的信息 423
8.3.4 文件操作 427
8.3.5 目录项缓存 431
8.4 处理VFS对象 436
8.4.1 文件系统操作 436
8.4.2 文件操作 450
8.5 标准函数 456
8.5.1 通用读取例程 457
8.5.2 失效机制 459
8.5.3 权限检查 461
8.6 小结 463
第9章 Ext文件系统族 464
9.1 简介 464
9.2 Ext2文件系统 465
9.2.1 物理结构 465
9.2.2 数据结构 470
9.2.3 创建文件系统 484
9.2.4 文件系统操作 485
9.3 Ext3文件系统 507
9.3.1 概念 508
9.3.2 数据结构 509
9.4 小结 511
第10章 无持久存储的文件系统 512
10.1 proc文件系统 512
10.1.1 /proc的内容 513
10.1.2 数据结构 519
10.1.3 初始化 522
10.1.4 装载proc文件系统 523
10.1.5 管理/proc数据项 525
10.1.6 读取和写入信息 528
10.1.7 进程相关的信息 530
10.1.8 系统控制机制 535
10.2 简单的文件系统 542
10.2.1 顺序文件 542
10.2.2 用libfs编写文件系统 546
10.2.3 调试文件系统 547
10.2.4 伪文件系统 549
10.3 sysfs 549
10.3.1 概述 550
10.3.2 数据结构 550
10.3.3 装载文件系统 554
10.3.4 文件和目录操作 556
10.3.5 向sysfs添加内容 562
10.4 小结 564
第11章 扩展属性和访问控制表 565
11.1 扩展属性 565
11.1.1 到虚拟文件系统的接口 566
11.1.2 Ext3中的实现 570
11.1.3 Ext2中的实现 576
11.2 访问控制表 577
11.2.1 通用实现 577
11.2.2 Ext3中的实现 580
11.2.3 Ext2中的实现 585
11.3 小结 585
第12章 网络 586
12.1 互联的计算机 586
12.2 ISO/OSI和TCP/IP参考模型 587
12.3 通过套接字通信 589
12.3.1 创建套接字 590
12.3.2 使用套接字 591
12.3.3 数据报套接字 595
12.4 网络实现的分层模型 595
12.5 网络命名空间 597
12.6 套接字缓冲区 599
12.6.1 使用套接字缓冲区管理数据 600
12.6.2 管理套接字缓冲区数据 602
12.7 网络访问层 603
12.7.1 网络设备的表示 603
12.7.2 接收分组 608
12.7.3 发送分组 614
12.8 网络层 615
12.8.1 IPv4 615
12.8.2 接收分组 617
12.8.3 交付到本地传输层 618
12.8.4 分组转发 619
12.8.5 发送分组 620
12.8.6 netfilter 623
12.8.7 IPv6 627
12.9 传输层 628
12.9.1 UDP 628
12.9.2 TCP 630
12.10 应用层 640
12.10.1 socket数据结构 640
12.10.2 套接字和文件 643
12.10.3 socketcall系统调用 644
12.10.4 创建套接字 645
12.10.5 接收数据 646
12.10.6 发送数据 647
12.11 内核内部的网络通信 647
12.11.1 通信函数 648
12.11.2 netlink机制 649
12.12 小结 654
第13章 系统调用 655
13.1 系统程序设计基础 655
13.1.1 追踪系统调用 656
13.1.2 支持的标准 658
13.1.3 重启系统调用 659
13.2 可用的系统调用 660
13.3 系统调用的实现 663
13.3.1 系统调用的结构 664
13.3.2 访问用户空间 670
13.3.3 追踪系统调用 670
13.4 小结 676
第14章 内核活动 678
14.1 中断 678
14.1.1 中断类型 678
14.1.2 硬件IRQ 680
14.1.3 处理中断 680
14.1.4 数据结构 682
14.1.5 中断电流处理 688
14.1.6 初始化和分配IRQ 692
14.1.7 处理IRQ 693
14.2 软中断 701
14.2.1 开启软中断处理 702
14.2.2 软中断守护进程 703
14.3 tasklet 704
14.3.1 创建tasklet 704
14.3.2 注册tasklet 704
14.3.3 执行tasklet 705
14.4 等待队列和完成量 706
14.4.1 等待队列 706
14.4.2 完成量 710
14.4.3 工作队列 711
14.5 小结 713
第15章 时间管理 714
15.1 概述 714
15.1.1 定时器的类型 714
15.1.2 配置选项 716
15.2 低分辨率定时器的实现 717
15.2.1 定时器激活与进程统计 717
15.2.2 处理jiffies 719
15.2.3 数据结构 720
15.2.4 动态定时器 721
15.3 通用时间子系统 725
15.3.1 概述 726
15.3.2 配置选项 727
15.3.3 时间表示 727
15.3.4 用于时间管理的对象 728
15.4 高分辨率定时器 736
15.4.1 数据结构 736
15.4.2 设置定时器 740
15.4.3 实现 740
15.4.4 周期时钟仿真 745
15.4.5 切换到高分辨率定时器 746
15.5 动态时钟 747
15.5.1 数据结构 747
15.5.2 低分辨率系统下的动态时钟 749
15.5.3 高分辨率系统下的动态时钟 751
15.5.4 停止和启动周期时钟 752
15.6 广播模式 755
15.7 定时器相关系统调用的实现 756
15.7.1 时间基准 756
15.7.2 alarm和setitimer系统调用 757
15.7.3 获取当前时间 758
15.8 管理进程时间 759
15.9 小结 760
第16章 页缓存和块缓存 761
16.1 页缓存的结构 762
16.1.1 管理和查找缓存的页 762
16.1.2 回写修改的数据 763
16.2 块缓存的结构 764
16.3 地址空间 766
16.3.1 数据结构 766
16.3.2 页树 768
16.3.3 地址空间操作 771
16.4 页缓存的实现 774
16.4.1 分配页 774
16.4.2 查找页 775
16.4.3 在页上等待 776
16.4.4 对整页的操作 777
16.4.5 页缓存预读 778
16.5 块缓存的实现 781
16.5.1 数据结构 782
16.5.2 操作 783
16.5.3 页缓存和块缓存的交互 783
16.5.4 独立的缓冲区 787
16.6 小结 792
第17章 数据同步 793
17.1 概述 793
17.2 pdflush机制 795
17.3 启动新线程 796
17.4 线程初始化 796
17.5 执行实际工作 798
17.6 周期性刷出 798
17.7 相关的数据结构 799
17.7.1 页状态 799
17.7.2 回写控制 800
17.7.3 可调参数 802
17.8 中央控制 802
17.9 超级块同步 804
17.10 inode同步 804
17.10.1 遍历超级块 805
17.10.2 考察超级块inode 805
17.10.3 回写单个inode 807
17.11 拥塞 809
17.11.1 数据结构 809
17.11.2 阈值 810
17.11.3 拥塞状态的设置和清除 811
17.11.4 在拥塞队列上等待 812
17.12 强制回写 813
17.13 膝上模式 814
17.14 用于同步控制的系统调用 815
17.15 完全同步 815
17.15.1 inode的同步 816
17.15.2 单个文件的同步 818
17.15.3 内存映射的同步 819
17.16 小结 820
第18章 页面回收和页交换 821
18.1 概述 821
18.1.1 可换出页 822
18.1.2 页颠簸 822
18.1.3 页交换算法 823
18.2 Linux内核中的页面回收和页交换 824
18.2.1 交换区的组织 824
18.2.2 检查内存使用情况 825
18.2.3 选择要换出的页 825
18.2.4 处理缺页异常 826
18.2.5 缩减内核缓存 826
18.3 管理交换区 826
18.3.1 数据结构 827
18.3.2 创建交换区 830
18.3.3 激活交换区 831
18.4 交换缓存 834
18.4.1 标识换出页 835
18.4.2 交换缓存的结构 838
18.4.3 添加新页 839
18.4.4 搜索一页 843
18.5 数据回写 844
18.6 页面回收 845
18.6.1 概述 845
18.6.2 数据结构 847
18.6.3 确定页的活动程度 850
18.6.4 收缩内存域 853
18.6.5 隔离LRU页和集中回收 856
18.6.6 收缩活动页链表 859
18.6.7 回收不活动页 862
18.7 交换令牌 867
18.8 处理交换缺页异常 870
18.8.1 换入页 870
18.8.2 读取数据 872
18.8.3 交换预读 873
18.9 发起内存回收 873
18.9.1 用kswapd进行周期性内存回收 873
18.9.2 在严重内存不足时换出页 877
18.10 收缩其他缓存 878
18.10.1 数据结构 878
18.10.2 注册和删除收缩器 879
18.10.3 收缩缓存 879
18.11 小结 880
第19章 审计 882
19.1 概述 882
19.2 审计规则 883
19.3 实现 884
19.3.1 数据结构 884
19.3.2 初始化 889
19.3.3 处理请求 890
19.3.4 记录事件 891
19.3.5 系统调用审计 893
19.4 小结 898
附录A 体系结构相关知识 899
A.1 概述 899
A.2 数据类型 900
A.3 对齐 900
A.4 内存页面 900
A.5 系统调用 901
A.6 字符串处理 901
A.7 线程表示 902
A.8 位操作和字节序 914
A.9 页表 916
A.10 杂项 916
A.11 小结 918
附录B 使用源代码 919
B.1 内核源代码的组织 919
B.2 用Kconfig进行配置 920
B.3 用Kbuild编译内核 930
B.4 有用的工具 935
B.5 调试和分析内核 942
B.6 用户模式Linux 945
B.7 小结 946
附录C 有关C语言的注记 947
C.1 GNU C编译器如何工作 947
C.2 内核的标准数据结构和技术 967
C.3 小结 984
附录D 系统启动 985
D.1 IA-32系统上与体系结构相关的设置 985
D.2 高层初始化 986
D.3 小结 998
附录E ELF二进制格式 999
E.1 布局和结构 999
E.2 内核中的数据结构 1006
E.3 小结 1018
附录F 内核开发过程 1019
F.1 简介 1019
F.2 内核代码树和开发的结构 1019
F.3 补丁的结构 1024
F.4 Linux和学术界 1030
F.5 小结 1035
参考文献 1036