Linux 0.1.1文件系统的源码阅读
linux 0.11编译方法
linux 0.11编译方法
Linux 0.11是Linux内核的一个早期版本,其编译方法相比现代版本有所不同。
下面是大致的编译步骤:
1.获取源代码
获取Linux 0.11的源代码。
这个版本的代码可以在历史存档中找到。
你可以从网络上找到存档并下载,或者使用像GitHub等代码托管平台上的存档。
2.准备编译环境
确保你的系统拥有合适的编译环境。
Linux 0.11是早期版本,可能需要特定的编译器和工具链。
一般来说,你需要安装合适版本的GCC编译器和相关的开发工具。
3.编辑Makefile
进入Linux 0.11源代码目录,在Makefile中设置适当的编译选项。
你可能需要调整编译器参数和其他配置,以适应你的系统环境。
4.运行编译命令
在Linux 0.11源代码目录中,运行适当的编译命令。
在这个版本中,可能有一个名为make或make all的命令可以启动编译过程。
5.处理编译错误
如果出现编译错误,需要根据错误信息进行调试和修复。
这个过程可能需要查看源代码,理解错误原因,并进行相应的修改。
6.生成内核镜像
一旦编译成功,你将会得到一个内核镜像文件。
这个文件可以用于启动系统。
请注意,Linux 0.11是一个非常早期的版本,其编译和构建流程可能相当复杂和不稳定。
同时,这个版本可能并不适用于现代硬件,可能需要进行适当的修改才能在当前系统上运行。
在学习和尝试编译早期版本的Linux内核时,请确保备份数据和系统,以免造成不可逆的损失。
Linux 0.1.1文件系统的源码阅读
Linux 0.11文件系统的源码阅读总结1.minix文件系统对于linux 0.11内核的文件系统的开发,Linus主要参考了Andrew S.Tanenbaum 所写的《MINIX操作系统设计与实现》,使用的是其中的1.0版本的MINIX文件系统。
而高速缓冲区的工作原理参见M.J.Bach的《UNIX操作系统设计》第三章内容。
通过对源代码的分析,我们可以将minix文件系统分为四个部分,如下如1-1。
●高速缓冲区的管理程序。
主要实现了对硬盘等块设备进行数据高速存取的函数。
●文件系统的底层通用函数。
包括文件索引节点的管理、磁盘数据块的分配和释放以及文件名与i节点的转换算法。
●有关对文件中的数据进行读写操作的函数。
包括字符设备、块设备、管道、常规文件的读写操作,由read_write.c函数进行总调度。
●涉及到文件的系统调用接口的实现,这里主要涉及文件的打开、关闭、创建以及文件目录等系统调用,分布在namei和inode等文件中。
图1-1 文件系统四部分之间关系图1.1超级块首先我们了解一下MINIX文件系统的组成,主要包括六部分。
对于一个360K软盘,其各部分的分布如下图1-2所示:图 1-2 建有MINIX文件系统的一个360K软盘中文件系统各部分的布局示意图注释1:硬盘的一个扇区是512B,而文件系统的数据块正好是两个扇区。
注释2:引导块是计算机自动加电启动时可由ROM BIOS自动读入得执行代码和数据。
注释3:逻辑块一般是数据块的2幂次方倍数。
MINIX文件系统的逻辑块和数据块同等大小对于硬盘块设备,通常会划分几个分区,每个分区所存放的不同的文件系统。
硬盘的第一个扇区是主引导扇区,其中存放着硬盘引导程序和分区表信息。
分区表中得信息指明了硬盘上每个分区的类型、在硬盘中其实位置参数和结束位置参数以及占用的扇区总数。
其结构如下图1-3所示。
图1-3 硬盘设备上的分区和文件系统对于可以建立不同的多个文件系统的硬盘设备来说,minix文件系统引入超级块进行管理硬盘的文件系统结构信息。
Linux内核中的Kconfig用法与说明
Linux内核中的Kconfig文件本节不对内核的Kconfig文件进行深入展开,更多Kconfig语法和说明请阅读<Documentation/kbuild/kconfig-language.txt>和<Documentation/kbuild/kconfig.txt>。
内核源码树每个目录下都还包含一个Kconfig文件,用于描述所在目录源代码相关的内核配置菜单,各个目录的Kconfig文件构成了一个分布式的内核配置数据库。
通过make menuconfig(make xconfig或者make gconfig)命令配置内核的时候,从Kconfig文件读取菜单,配置完毕保存到文件名为.config的内核配置文件中,供Makefile文件在编译内核时使用。
1.1.1 Kconfig基本语法如程序清单0.1所示代码摘自<drivers/char/Kconfig>文件,是一个比较典型的Kconfig文件片段,包含了Kconfig的基本语法。
程序清单0.1drivers/char/Kconfig片段menu "Character devices"source "drivers/tty/Kconfig"config DEVKMEMbool "/dev/kmem virtual device support"default yhelpSay Y here if you want to support the /dev/kmem device. The/dev/kmem device is rarely used, but can be used for certainkind of kernel debugging operations.When in doubt, say "N".……endmenu1.子菜单通过menu和endmenu来定义一个子菜单,程序清单0.1所示代码定义了一个“Character devices”子菜单,子菜单在界面中用“--->”表示,如图0.1所示。
linux 读取文件的原理
linux 读取文件的原理
Linux 读取文件的原理主要涉及到操作系统、文件系统和硬件等多个方面。
下面是一个简要的概述:
1.文件系统:Linux 系统使用的是类Unix 的文件系统,称为Ext4。
文件系统负责管理文件在硬盘上的存储和访问,以及文件的权限和属性等信息。
当一个程序试图读取一个文件时,文件系统会接收到这个请求,并查找文件在硬盘上的位置。
2.打开文件:要读取一个文件,首先需要打开这个文件。
在Linux 中,打开文件是通过系统调用(如open() 或fopen())实现的。
这些系统调用会向操作系统发出请求,请求中包含文件名和打开文件的模式(例如只读、写入等)。
操作系统会查找文件并返回一个文件描述符,这个文件描述符是一个整数,用于标识已经打开的文件。
3.读取文件数据:一旦文件被打开,就可以通过系统调用(如read() 或fread())来读取文件的内容。
这些系统调用会向操作系统发出请求,请求中包含文件描述符、读取的起始位置和要读取的字节数。
操作系统会将读取的请求传递给硬件,硬件会从硬盘中读取相应的数据,并将其存储在内存中。
4.关闭文件:当读取完文件后,需要通过系统调用(如close() 或fclose())来关闭文件。
这个系统调用会将文件描述符释放回操作系统,以便其他程序可以使用它。
linux0.01内核
linux0.01内核Linux0.01内核分析的一点心得linux(linux教程linux培训)0.01内核基本上分析完了,高版本的内核也看了一点。
有一点心得与大家分享一下吧!这里我并不打算说具体的技术方面的东西,而是针对读内核的方法,谈谈自己一点感受。
我前段时间主要看的是0.01版本的内核。
Linux0.01是Linux 的"祖师爷"Linus完成的最早的一个Linux版本,其内核编译后仅仅只有512K,麻雀虽小,五脏俱全,0.01包括了从软盘启动、文件系统、控制台管理的操作系统完整功能,并提供了不少标准的用户接口,具体有kernel, boot, fs, init,mm等几个部分,没有网络部分。
为什么选择Linux0.01?各位大虾一看到0.01肯定直摇头:哎呀,都什么时代的东东了,有看的必要么?笔者当初选择0.01并没有太多的想法,只是Tm-linux小组刚开始选择的是0.01,于是就开始读吧,现在仔细想想,读Linux0.01对于初学者来说可能更容易上手些。
可能有下面的几个好处吧1)0.01的代码量较小。
很多同学都曾有成为Linux高手的欲望,也曾抱回若干砖头书,但Linux的发展何其之快,而coder 又是黑客型高手,往往坚持不了多长时间而中途放弃!2)0.01的代码简单而精简(这个简单当然是相对于后续版本而言的)。
实际上0.01完成的就是一个操作系统的最初的要求,包括启动,进程调度,内存管理等,而这些往往与硬件结合,在看高版本的内核时往往还没有接触到这些硬件知识,层层下调已经把你搞糊涂了。
3)从低版本看更能看到技术进步的源动力,比如0.01的内核很小,其启动代码可以只放在一个扇区内,而后续版本的内核较大,无法放入一个扇区内,于是压缩核心的装入方法诞生了。
再如内存管理,0.01的内存管理比较简单,内存的申请释放直接通过使用前申请,使用后释放,但考虑以后的版本功能复杂,如何解决可能的"外碎片"问题,如何解决内存不足的问题,于是对后续版本采用的"伙伴算法",slab技术,页面守护进程有更好的理解。
Linux0.01内核源代码及注释
Bootsect.s(1-9)!! SYS_SIZE is the number of clicks (16 bytes) to be loaded.! 0x3000 is 0x30000 bytes = 196kB, more than enough for current! versions of linux ! SYS_SIZE 是要加载的节数(16 字节为1 节)。
0x3000 共为1 2 3 4 5 60x7c000x00000x900000x100000xA0000system 模块代码执行位置线路0x90200! 0x30000 字节=192 kB(上面Linus 估算错了),对于当前的版本空间已足够了。
!SYSSIZE = 0x3000 ! 指编译连接后system 模块的大小。
参见列表1.2 中第92 的说明。
! 这里给出了一个最大默认值。
!! bootsect.s (C) 1991 Linus Torvalds!! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves! iself out of the way to address 0x90000, and jumps there.!! It then loads 'setup' directly after itself (0x90200), and the system! at 0x10000, using BIOS interrupts.!! NOTE! currently system is at most 8*65536 bytes long. This should be no! problem, even in the future. I want to keep it simple. This 512 kB! kernel size should be enough, especially as this doesn't contain the! buffer cache as in minix!! The loader has been made as simple as possible, and continuos! read errors will result in a unbreakable loop. Reboot by hand. It! loads pretty fast by getting whole sectors at a time whenever possible.!! 以下是前面这些文字的翻译:! bootsect.s (C) 1991 Linus Torvalds 版权所有!! bootsect.s 被bios-启动子程序加载至0x7c00 (31k)处,并将自己! 移到了地址0x90000 (576k)处,并跳转至那里。
linux 文件描述 0 1 2 的用法
在Linux 和类Unix 操作系统中,每个进程都有三个预定义的标准文件描述符,它们分别是:•文件描述符0 (STDIN):代表标准输入,通常关联到键盘或从其他程序接收输入的数据流。
当你运行一个命令并从键盘输入信息时,这些信息就是通过文件描述符0 提供给命令进程的。
•文件描述符1 (STDOUT):代表标准输出,它是进程正常输出数据的通道,默认情况下会显示在终端屏幕上。
例如,当你运行ls命令并列出目录内容时,这些内容就会通过文件描述符 1 输出到屏幕。
•文件描述符2 (STDERR):代表标准错误,用于输出错误信息、警告和其他非正常输出。
即使stdout 被重定向,stderr 仍然可以独立地将错误信息发送到屏幕,这样可以确保无论何种情况,错误信息都能够被用户看到。
这三种文件描述符可以用在shell 脚本编程以及命令行重定向操作中,例如:•重定向:o command > file.txt将命令的标准输出重定向到file.txt文件中,覆盖原有内容。
o command 2> error.log将命令的标准错误输出重定向到error.log文件中,同样会覆盖原文件内容。
o command > output.txt 2>&1则是将标准错误重定向到与标准输出相同的文件描述符上,这意味着标准错误也会被追加到output.txt文件中。
•管道:o command1 | command2可以将第一个命令的标准输出作为第二个命令的标准输入。
•文件描述符复制和重定向:o exec 3<&0创建一个新的文件描述符3,并使其与标准输入(文件描述符0)共享同一个输入源。
o command 2>&1将标准错误重定向至标准输出,此时两者都会输出到同一位置。
这些功能使得Linux 下的输入输出管理变得非常灵活,可以在编写脚本和处理程序输出时实现精确控制。
在linux下实现读者写者问题源代码
在linux下实现读者写者问题源代码读者写者问题是计算机科学中的一个经典同步问题,用于描述多个读者和写者对共享资源的访问。
在这个问题中,多个读者可以同时读取共享资源,但是写者在写入共享资源时必须独占访问。
在Linux下,我们可以使用线程和互斥锁来实现读者写者问题。
下面是一个简单的源代码示例:```c#include <stdio.h>#include <stdlib.h>#include <pthread.h>#define READERS_COUNT 5#define WRITERS_COUNT 2pthread_mutex_t mutex;pthread_cond_t cond_reader, cond_writer;int readers = 0;int writers = 0;void *reader(void *arg) {int id = *(int *)arg;while (1) {pthread_mutex_lock(&mutex);while (writers > 0) {pthread_cond_wait(&cond_reader, &mutex); }readers++;pthread_mutex_unlock(&mutex);// 读取共享资源printf("Reader %d is reading\n", id);pthread_mutex_lock(&mutex);readers--;if (readers == 0) {pthread_cond_signal(&cond_writer);}pthread_mutex_unlock(&mutex);}pthread_exit(NULL);}void *writer(void *arg) {int id = *(int *)arg;while (1) {pthread_mutex_lock(&mutex);while (readers > 0 || writers > 0) {pthread_cond_wait(&cond_writer, &mutex); }writers++;pthread_mutex_unlock(&mutex);// 写入共享资源printf("Writer %d is writing\n", id);pthread_mutex_lock(&mutex);writers--;pthread_cond_signal(&cond_writer);pthread_cond_broadcast(&cond_reader);pthread_mutex_unlock(&mutex);}pthread_exit(NULL);}int main() {pthread_t readers[READERS_COUNT];pthread_t writers[WRITERS_COUNT];int reader_ids[READERS_COUNT];int writer_ids[WRITERS_COUNT];pthread_mutex_init(&mutex, NULL);pthread_cond_init(&cond_reader, NULL);pthread_cond_init(&cond_writer, NULL);// 创建读者线程for (int i = 0; i < READERS_COUNT; i++) {reader_ids[i] = i + 1;pthread_create(&readers[i], NULL, reader, &reader_ids[i]); }// 创建写者线程for (int i = 0; i < WRITERS_COUNT; i++) {writer_ids[i] = i + 1;pthread_create(&writers[i], NULL, writer, &writer_ids[i]); }// 等待线程结束for (int i = 0; i < READERS_COUNT; i++) {pthread_join(readers[i], NULL);}for (int i = 0; i < WRITERS_COUNT; i++) {pthread_join(writers[i], NULL);}pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond_reader);pthread_cond_destroy(&cond_writer);return 0;}```在这个源代码中,我们使用了互斥锁(`pthread_mutex_t`)和条件变量(`pthread_cond_t`)来实现读者写者问题的同步。
Linux内核源代码(free)
Linux系统的好处 Linux的运行及相关基本概念
什么是Linux?
Linux是一个类Unix(Unix-like)的操作系统, 在1991年发行了它的第一个版本 在Linux内核维护网站上,“What is Linux?”
Portable Operating System Interface Standard 可移植操作系统接口标准 由IEEE制订,并由ISO接受为国际标准。 Institute for Electrical and Electronic Engineers 电气电子工程师学会[美] International Organization for Standardization 国际标准化组织 制定各行各业各种产品和服务的技术规范(国际标准)
Linux简介
什么是Linux? “Linux”在不同的语境下的含义 Linux发展简史 Linux操作系统的主要内容 Linux版本
内核版本 发行版本
Linux系统的好处 Linux的运行及相关基本概念
“Linux”
在不同的语境下,“Linux”具有不同的内涵,例 如:
Linux发展简史
1991年11月,芬兰赫尔辛基大学的学生 Linus Torvalds写了个小程序,后来取名为Linux,放在 互联网上。他表达了一个愿望,希望借此搞出一 个操作系统的“内核”来,这完全是一个偶然事 件 1993,在一批高水平黑客的参与下,诞生了Linux 1.0 版 1994年,Linux 的第一个商业发行版 Slackware 问 世
基于I386的Linux使用int 0x80进行系统调用
I386系统的基本概念
代码的运行 堆栈的概念 内核态与用户态 中断/异常/系统调用 虚拟内存
linux中tree的源码
linux中tree的源码全文共四篇示例,供读者参考第一篇示例:在Linux操作系统中,tree命令是一款非常实用的工具,它可以帮助用户以树状图的形式展示文件夹及文件的结构,让用户更直观地了解目录的层次关系。
不过,你是否想过tree命令的背后是如何实现的呢?其实,tree命令的源码是开源的,我们可以通过阅读其源码来深入了解其实现原理。
tree命令的源码主要由C语言编写,其核心功能在tree.c文件中实现。
在阅读源码之前,我们需要了解tree命令的基本功能:1. 遍历指定目录下的所有文件夹及文件;2. 以树状图的形式展示目录结构;3. 支持控制输出格式,如显示文件大小、文件权限等信息;4. 支持过滤指定文件或文件夹;5. 支持递归展示子目录。
接下来,让我们深入分析tree命令的源码实现:1. 主函数:tree命令的主函数主要负责解析命令行参数,并调用相应的函数实现功能。
在主函数中,通过解析命令行参数获取用户的选项,如-a(显示所有文件)、-h(以人类可读的形式显示文件大小)等。
2. 遍历目录:tree命令的核心功能是遍历目录树并以树状图的形式展示。
在tree.c文件中,定义了一个名为print_tree的函数,该函数通过递归方式遍历目录,并输出目录结构。
在遍历目录时,需要注意排除当前目录和父目录(.和..)以及过滤用户指定的文件或文件夹。
3. 输出格式:tree命令支持多种输出格式,如显示文件大小、文件权限等信息。
在tree.c文件中,定义了多个辅助函数用于输出文件信息,如print_size函数用于输出文件大小,print_mode函数用于输出文件权限等。
4. 递归展示:当tree命令遍历目录时,如果遇到子目录,需要递归展示子目录下的文件及目录。
在print_tree函数中,通过调用自身实现递归展示目录。
递归展示子目录是tree命令实现树状展示的关键之一。
第二篇示例:在Linux系统中,tree命令是一个非常常用的工具,它可以以树状结构显示指定目录下的所有文件和子目录。
怎样读Linux内核源代码
Linux内核分析方法2010-9-12Linux的最大的好处之一就是它的源码公开。
同时,公开的核心源码也吸引着无数的电脑爱好者和程序员;他们把解读和分析Linux的核心源码作为自己的最大兴趣,把修改Linux 源码和改造Linux系统作为自己对计算机技术追求的最大目标。
Linux内核源码是很具吸引力的,特别是当你弄懂了一个分析了好久都没搞懂的问题;或者是被你修改过了的内核,顺利通过编译,一切运行正常的时候。
那种成就感真是油然而生!而且,对内核的分析,除了出自对技术的狂热追求之外,这种令人生畏的劳动所带来的回报也是非常令人着迷的,这也正是它拥有众多追随者的主要原因:•首先,你可以从中学到很多的计算机的底层知识,如后面将讲到的系统的引导和硬件提供的中断机制等;其它,象虚拟存储的实现机制,多任务机制,系统保护机制等等,这些都是非都源码不能体会的。
等等,这些都是非读源码不能体会的。
•同时,你还将从操作系统的整体结构中,体会整体设计在软件设计中的份量和作用,以及一些宏观设计的方法和技巧:Linux的内核为上层应用提供一个与具体硬件不相关的平台;同时在内核内部,它又把代码分为与体系结构和硬件相关的部分,和可移植的部分;再例如,Linux虽然不是微内核的,但他把大部分的设备驱动处理成相对独立的内核模块,这样减小了内核运行的开销,增强了内核代码的模块独立性。
•而且你还能从对内核源码的分析中,体会到它在解决某个具体细节问题时,方法的巧妙:如后面将分析到了的Linux通过Botoom_half机制来加快系统对中断的处理。
•最重要的是:在源码的分析过程中,你将会被一点一点地、潜移默化地专业化。
一个专业的程序员,总是把代码的清晰性,兼容性,可移植性放在很重要的位置。
他们总是通过定义大量的宏,来增强代码的清晰度和可读性,而又不增加编译后的代码长度和代码的运行效率;他们总是在编码的同时,就考虑到了以后的代码维护和升级。
甚至,只要分析百分之一的代码后,你就会深刻地体会到,什么样的代码才是一个专业的程序员写的,什么样的代码是一个业余爱好者写的。
如何查看 linux 内核源代码
arch 这个子目录包含了此核心源代码所支持的硬件体系结构相关的核心代码。如对于X86平台就是i386。
include 这个目录包括了核心的大多数include文件。另外对于每种支持的体系结构分别有一个子目录。
init 此目录包含核心启动代码。
mm 此目录包含了所有的内存管理代码。与具体硬件体系结构相关的内存管理代码位于arch/*/mm目录下,如对应于X86的就是arch/i386/mm/fault.c 。
kernel 主要核心代码。同时与处理器结构相关代码都放在arch/*/kernel目录下。
net 核心的网络部分代码。里面的每个子目录对应于网络的一个方面。
lib 此目录包含了核心的库代码。与处理器结构相关库代码被放在arch/*/lib/目录下。
scripts此目录包含用于配置核心的脚本文件。
Documentation 此目录是一些文档,起参考作用。
俗话说:“工欲善其事,必先利其器”。 阅读象Linux核心代码这样的复杂程序令人望而生畏。它象一个越滚越大的雪球,阅读核心某个部分经常要用到好几个其他的相关文件,不久你将会忘记你原来在干什么。所以没有一个好的工具是不行的。由于大部分爱好者对于Window平台比较熟悉,并且还是常用Window系列平台,所以在此我介绍一个Window下的一个工具软件:Source Insight。这是一个有30天免费期的软件,可以从下载。安装非常简单,和别的安装一样,双击安装文件名,然后按提示进行就可以了。安装完成后,就可启动该程序。这个软件使用起来非常简单,是一个阅读源代码的好工具。它的使用简单介绍如下:先选择Project菜单下的new,新建一个工程,输入工程名,接着要求你把欲读的源代码加入(可以整个目录加)后,该软件就分析你所加的源代码。分析完后,就可以进行阅读了。对于打开的阅读文件,如果想看某一变量的定义,先把光标定位于该变量,然后点击工具条上的相应选项,该变量的定义就显示出来。对于函数的定义与实现也可以同样操作。别的功能在这里就不说了,有兴趣的朋友可以装一个Source Insight,那样你阅读源代码的效率会有很大提高的。怎么样,试试吧!
linux中tree的源码
Linux中tree的源码tree 是一个在Linux 系统中常用的命令行工具,用于显示目录结构的树形图。
它的源码是用C 语言编写的。
以下是一个简单的 tree 命令的源码示例。
这个示例版本非常简单,不包含所有 tree 命令的功能,但它演示了如何使用递归函数来显示目录树。
c复制代码#include<stdio.h>#include<stdlib.h>#include<string.h>#include<dirent.h>#include<sys/stat.h>#include<unistd.h>#define MAX_PATH 1024void print_directory(const char *path, int depth) {DIR *dir;struct dirent *entry;char full_path[MAX_PATH];if (!(dir = opendir(path))) {perror("opendir");return;}while ((entry = readdir(dir))) {if (strcmp(entry->d_name, ".") == 0 ||strcmp(entry->d_name, "..") == 0) {continue;}snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name);for (int i = 0; i < depth; i++) {printf(" ");}printf("%s\n", entry->d_name);if (entry->d_type == DT_DIR) {print_directory(full_path, depth + 1);}}closedir(dir);}int main(int argc, char *argv[]) {if (argc != 2) {fprintf(stderr, "Usage: %s <directory>\n", argv[0]);return1;}print_directory(argv[1], 0);return0;}这个示例中的 print_directory 函数使用递归方式遍历指定目录下的所有文件和子目录,并根据目录的深度打印出相应的缩进。
Linux 源代码分析
Linux内核(2.6.13.2)源代码分析苗彦超摘要:1系统启动1.1汇编代码head.S及以前设置CPU状态初值,创建进程0,建立进程堆栈:movq init_rsp(%rip), %rsp,init_rsp定义.globl init_rspinit_rsp:.quad init_thread_union+THREAD_SIZE-8即将虚地址init_thread_union+THREAD_SIZE-8作为当前进程(进程0)核心空间堆栈栈底,init_thread_union定义于文件arch/x86_64/kernel/init_task.c中:union thread_union init_thread_union __attribute__((__section__(".data.init_task"))) ={INIT_THREAD_INFO(init_task)};INIT_THREAD_INFO定义于文件include/asm-x86_64/thread_info.h中,初始化init_thread_union.task = &init_task,init_task同样定义于文件init_task.c中,初始化为:struct task_struct init_task = INIT_TASK(init_task);INIT_TASK宏在include/linux/init_task.h中定义。
全部利用编译时静态设置的初值,将进程0的控制结构设置完成,使进程0可以按普通核心进程访问。
init_task.mm = NULL; init_task.active_mm = INIT_MM(init_mm), init_m = “swapper”INIT_MM将init_mm.pgd初始化为swapper_pg_dir,即init_level4_pgt,定义与head.S中。
【原创】Linux内核源码分析之进程概要及调度时机
【原创】Linux内核源码分析之进程概要及调度时机❝❞进程概要及调度时机这篇⽂章从 Linux 内核层⾯分析进程概要及调度时机。
0 本⽂内容⼀分钟速览如果读者没有耐⼼看完整篇⽂章,下⾯是本⽂的核⼼内容预览,⼀分钟内能读完。
0.1 进程概要•进程是对物理世界的建模抽象,每个进程对应⼀个 task_struct 数据结构,这个数据结构包含了进程的所有的信息。
•在 Linux 内核中,不会区分线程和进程的概念,线程也是通过进程来实现的,线程和进程的唯⼀区别就是:线程没有独⽴的资源,进程有。
•所有的进程都是通过其他进程创建出来的,因此,整个进程组织为⼀棵进程树。
•0 号进程是⽆中⽣有凭空产⽣的,是静态定义出来的,是所有进程的祖先,创建了 INIT (1号)和 kthreadd (2号进程)。
0.2 进程调度时机•系统调⽤ yield 、 pause 会使得当前进程让出 CPU,随后进⾏⼀次进程调度。
•系统调⽤ futex(wait)等待某个信号量,将进程设置为 TASK_INTERRUPTIBLE 状态,然后进⾏⼀次进程调度。
•进程在退出的时候,会系统调⽤到 exit ⽅法,将当前进程设置为 TASK_DEAD 之后,进⾏⼀次进程调度。
•在创建新进程、唤醒进程、周期调度过程中,内核会给当前进程设置⼀个需要调度的标志,然后在下⼀次中断返回到⽤户空间时,进⾏⼀次调度。
•每颗 CPU 都会绑定⼀个 IDLE 进程,没事就在 CPU 上⽆聊地空转,偶尔进⾏⼀次进程调度。
1 进程概要 1.1 进程是对物理世界的建模抽象⼈们在⾯对⼀个问题束⼿⽆策的时候,经常会创造⼀个概念,然后基于这个概念来演化出⼀个系统来解决这个问题。
进程的概念就是⼈类发明出来,为了解决物理世界想要同时做若⼲件事情的需求,最终演化出了进程⼦系统。
关于进程的基本知识⽹上有很多,这⾥说下我的理解:••加载器将可执⾏程序⽂件(Linux 中是 ELF 格式)加载到操作系统,操作系统中就多了⼀个进程。
linux中tree的源码
Tree是一个在Linux环境下常用的命令行工具,用于以树状结构展示目录结构。
它有助于用户快速了解目录中的文件和子目录的层次关系,提高了查看目录结构的效率。
Tree的源码主要由C语言编写,主要包括对目录结构的操作以及输出格式的处理。
在源码中,可以看到对文件和目录的遍历操作,以及递归调用来实现树状结构的展示。
同时,源码中还包括了对命令行参数的解析和处理,以及对输出格式的控制,使得Tree可以根据用户的需求来展示目录结构。
在源码中,还可以看到对路径处理、文件类型判断等相关操作,以保证Tree在展示目录结构时能够准确地反映出文件和子目录之间的关系。
同时,对于不同操作系统的兼容性以及错误处理也都有相应的代码实现,以保证Tree在不同环境中都能正常运行。
总的来说,Tree的源码实现了对目录结构的递归遍历和树状展示,并且考虑了不同环境下的兼容性和用户需求,使得Tree成为了Linux环境下一个非常好用的目录结构展示工具。
LINUXCNC源程序原理说明
opLINUXCNC源程序学习源程序的树结构如下:Overview of the emc2 directory (generated by tree -I .git -d) :.|-- app-defaults|-- bin (user mode binaries)|-- configs| |-- 5axis| |-- boss| |-- common| |-- dallur-thc| |-- demo_mazak (sample mazak config files)| |-- demo_sim_cl (sample sim with ladder IO)| |-- demo_step_cl (sample stepper with ladder IO)| |-- etch-servo| |-- halui_halvcp| |-- hexapod-sim| |-- lathe-pluto| |-- m5i20 (sample servo using Mesa PCI)| |-- max| |-- motenc (sample servo using Vital PCI)| |-- nist-lathe| |-- plasma-thc| |-- plasma-thc-sim| |-- ppmc| |-- puma| |-- scara| |-- sim (simulated motion and IO)| |-- stepper (parport stepper driver)| |-- stepper-gantry| |-- stepper-xyza| |-- stg (sample servo using STG ISA)| |-- univpwm (sample PICO servo generator)| |-- univstep (sample PICO stepper generator)| `-- vti|-- debian (files needed to build deb packages)| |-- extras-Ubuntu-5.10 (extra files for Ubuntu 5.10)| | |-- etc| | | |-- modprobe.d| | | |-- udev| | | | |-- rules.d| | | | `-- scripts| | | `-- xdg| | | `-- menus| | | `-- applications-merged| | |-- applications| | |-- desktop-directories| | `-- pixmaps| |-- extras-Ubuntu-6.06 (extra files for building on Ubuntu 6.06 Dapper Drake) | | |-- etc| | | |-- modprobe.d| | | |-- udev| | | | |-- rules.d| | | | `-- scripts| | | `-- xdg| | | `-- menus| | | `-- applications-merged| | `-- usr| | `-- share| | |-- applications| | |-- desktop-directories| | `-- pixmaps| |-- extras-Ubuntu-7.10 (extra files for building on Ubuntu 7.10)| | |-- etc| | | |-- modprobe.d| | | |-- udev| | | | `-- rules.d| | | `-- xdg| | | `-- menus| | | `-- applications-merged| | `-- usr| | `-- share| | |-- applications| | |-- desktop-directories| | `-- pixmaps| |-- extras-Ubuntu-8.04 (extra files for building on Ubuntu 8.04 Hardy Heron) | | |-- etc| | | |-- modprobe.d| | | `-- xdg| | | `-- menus| | | `-- applications-merged| | `-- usr| | `-- share| | |-- applications| | |-- desktop-directories| | `-- pixmaps| |-- extras-sim-Ubuntu-5.10 (extra files for sim package for Ubuntu 5.10)| | |-- etc| | | `-- xdg| | | `-- menus| | | `-- applications-merged| | `-- usr| | |-- desktop-directories| | `-- pixmaps| `-- extras-sim-Ubuntu-6.06 (extra files for sim package for Ubuntu 6.06 Dapper Drake)| |-- etc| | `-- xdg| | `-- menus| | `-- applications-merged| `-- usr| `-- share| |-- applications| |-- desktop-directories| `-- pixmaps|-- docs (All the important and relevant Docs.)| |-- help| |-- html (html version of docs - some generated from lyx)| |-- man (man pages)| | |-- man1| | |-- man3| | `-- man9| `-- src (API and source notes should be in each src dir.) (source for the handbooks) (top level .lyx files) | |-- code| |-- common (shared .lyx files and images, such as glossary, GPLD license)| |-- config| |-- gcode (.lyx files, images, etc. for G-Code documentation)| |-- gui (.lyx files, images, etc. for GUI documentation)| |-- hal (.lyx files, images, etc. for HAL documentation)| |-- install| |-- ladder| |-- motion| `-- quickstart|-- include (headers installed here - originals in src/xxx/)|-- lib (user mode object files)| `-- python| |-- rs274| `-- yapps|-- nc_files (Sample NC files)|-- rtlib (kernel mode object files, only after a successfull compile)|-- scripts(bash scripts like linuxcnc, realtime, rip-environment, etc.)|-- share| |-- axis| | |-- images| | `-- tcl| |-- emc| `-- locale| |-- de| | `-- LC_MESSAGES| |-- es| | `-- LC_MESSAGES| |-- hu| | `-- LC_MESSAGES| |-- it| | `-- LC_MESSAGES| |-- pt_BR| | `-- LC_MESSAGES| |-- ro| | `-- LC_MESSAGES| |-- ru| | `-- LC_MESSAGES| |-- se| | `-- LC_MESSAGES| |-- sr| | `-- LC_MESSAGES| `-- zh_CN| `-- LC_MESSAGES|-- src (source tree - configure script, top level makefile, Makefile.inc, etc)| || |-- depends (generated dependency tree)| || |-- emc (actual LinuxCNC code)| | |-- canterp (interpreter for canonical commands)| | |-- ini (inifile related operations)| | |-- iotask (IO interface, lots of HAL pins)| | |-- kinematics (trajectory planner and kinematics)| | |-- motion (motion controller, talks through SHM to the rest of EMC)| | |-- nml_intf (emc specific NML implementation, all messages sent in emc)| | |-- rs274ngc (the rs274 g-code interpreter)| | |-- sai| | |-- task (core component in emc, dispatches actions to other parts)| | `-- usr_intf (interfaces for some GUIs, and other interfaces: AXIS, halui, stepconf)| | |-- axis| | | |-- etc| | | |-- extensions| | | `-- scripts| | `-- stepconf| |-- hal (the Hardware Abstraction Layer, provides a unified interface across all hardware) | | |-- classicladder| | | `-- projects_examples| | |-- components| | |-- drivers| | | |-- m5i20| | | | |-- bit| | | | `-- hostmot5_src| | | |-- mesa-hostmot2| | | | |-- doc| | | | | `-- SOURCE| | | | `-- 7i43| | | | |-- CPLD| | | | | `-- SOURCE| | | | `-- SOURCE| | | |-- mesa7i43-firmware| | | | |-- gpio| | | | | `-- source| | | | |-- hostmot2| | | | | `-- src| | | | `-- source| | | |-- mesa_5i2x| | | | `-- firmware| | | |-- pluto_servo_firmware| | | `-- pluto_step_firmware| | |-- user_comps| | | |-- devices| | | `-- vcp| | `-- utils| | `-- halgui| |-- libnml (a clean implementation of RCSLIB) | | |-- buffer| | |-- cms| | |-- inifile| | |-- linklist| | |-- nml| | |-- os_intf| | |-- posemath| | `-- rcs| |-- module_helper| |-- objects| | |-- emc| | | |-- canterp| | | |-- ini| | | |-- iotask| | | |-- motion| | | |-- nml_intf| | | |-- rs274ngc| | | |-- sai| | | |-- task| | | `-- usr_intf| | | `-- axis| | | `-- extensions| | |-- hal| | | |-- classicladder| | | |-- components| | | |-- drivers| | | `-- utils| | |-- libnml| | | |-- buffer| | | |-- cms| | | |-- inifile| | | |-- linklist| | | |-- nml| | | |-- os_intf| | | |-- posemath| | | `-- rcs| | |-- rtapi| | |-- rtemc| | | |-- kinematics| | | `-- motion| | |-- rthal| | | |-- classicladder| | | |-- components| | | `-- utils| | |-- rtlibnml| | | `-- posemath| | `-- rtobjects| | `-- hal| | `-- components| |-- po (Translation files for i18n support)| |-- rtapi (*.c and *.h for RTAPI) (unified RT API, wraps over RTLinux, RTAI and sim) | | `-- examples (testing examples for the RTAPI)| | |-- extint| | |-- fifo| | |-- semaphore| | |-- shmem| | `-- timer| `-- tests|-- tcl (tkemc.tcl, mini.tcl - the tcl GUI's)| |-- bin| `-- scripts`-- tests|-- abs.0|-- and-or-not-mux.0|-- basic|-- ccomp| |-- lathe-comp| |-- mill-g90g91g92| |-- mill-line-arc-entry| `-- mill-zchanges|-- counter-encoder.0|-- flipflop.0|-- limit3.0|-- limit3.1|-- limit3.2|-- modparam.0|-- overrun|-- oword| `-- sub.0|-- save.0|-- save.1|-- source.0|-- stepgen.0|-- stepgen.1|-- stepgen.2|-- threads.0`-- timedelay.0Overview of the emc2 install dirs:/ (file system root)|||--- etc/| || \--- init.d/| || \--- realtime (realtime start/stop script)|||--- $(prefix) (default: /usr/local)| | (all the following $xxxxdir are configurable through autoconf | || |--- bin/ (known as $bindir, files from EMC2/bin)| || |--- sbin/ (known as $sbindir, )| || |--- etc/ (known as $sysconfdir, config files and subdirs from configs/) | || |--- lib/ (known as $libdir, lib files *.so from libs/)| || \--- share/| || \--- emc/| || || |--- docs/| || |--- handbooks/| | || | \--- (PDF versions of handbooks)| || \--- nc_files/| || \--- (Sample NC files)||--- $MAN_DIR/ (default: /usr/local/man)| || |--- man1/| | || || || \--- man3/| |||\--- $moduledir/ (based on where ./configure finds the RTOS modules)根据这个结构树,我们可以清楚的知道每一个文件夹,每一个子文件的作用,包括了接口,硬件抽象层,实时内核等等部分。
[重点]linux源码分析
[重点]linux源码分析linux源码分析Linux内核源代码中的C语言代码Linux 内核的主体是以 GNU的 C 语言编写的,GNU为此提供了编译工具gcc。
GNU对 C 语言本身(在 ANSI C 基础上)做了不少扩充,可能是读者尚未见到过的。
另一方面,由于内核代码,往往会用到一些在应用程序设计中不常见的语言成分或编程技巧,也许使读者感到陌生。
本书并非介绍 GNU C语言的专著,也非技术手册,所以不在这里一一列举和详细讨论这些扩充和技巧。
再说,离开具体的情景和上下文,罗列一大堆规则,对于读者恐怕也没有多大帮助。
所以,我们在这里只是对可能会影响读者阅读 Linux 内核源程序,或使读者感到困惑的一些扩充和技巧先作一些简单的介绍。
以后,随着具体的情景和代码的展开,在需要时还会结合实际加以补充。
首先,gcc 从 C++语言中吸收了“inline”和“const”。
其实,GNU 的 C 和C++是合为一体的,gcc既是 C 编译又是 C++编译,所以从 C++中吸收一些东西到 C 中是很自然的。
从功能上说,inline 函数的使用与#define 宏定义相似,但更有相对的独立性,也更安全。
使用 inline函数也有利于程序调试。
如果编译时不加优化,则这些inline 就是普通的、独立的函数,更便于调试。
调试好了以后,再采用优化重新编译一次,这些 inline函数就像宏操作一样融入了引用处的代码中,有利于提高运行效率。
由于 inline 函数的大量使用,相当一部分的代码从.c 文件移入了.h 文件中。
还有,为了支持 64 位的CPU结构(Alpha 就是 64 位的),gcc 增加了一种新的基本数据类型“longlong int”,该类型在内核代码中常常用到。
许多 C 语言都支持一些“属性描述符”(attribute),如“aligned”、“packed”等等;gcc 也支持不少这样的描述符。
这些描述符的使用等于是在 C 语言中增加了一些新的保留字。
glibc 源码 解读
glibc 源码解读
glibc (GNU C Library) 是GNU 和Linux 操作系统的标准C 库,它提供了许多用于开发应用程序的基础函数,如内存管理、文件I/O、网络编程等。
由于glibc 是开源的,因此我们可以直接查看其源代码,了解其内部实现。
解读glibc 源码需要具备一定的C 语言基础和系统编程知识。
下面是一些建议,帮助你开始解读glibc 源码:
了解glibc 的功能和模块:首先,你需要了解glibc 的主要功能和模块,例如内存管理、文件I/O、网络编程等。
这样可以帮助你更好地理解各个模块之间的联系和协作。
从简单函数开始:从简单的函数开始阅读,例如打开文件、读取文件、内存分配等。
这些函数通常是glibc 中的基础函数,其实现相对简单,但包含了glibc 的基本思想和机制。
跟踪调用关系:在阅读源码时,要关注函数之间的调用关系,了解每个函数的作用和输入输出参数。
这有助于你理解整个程序的流程和逻辑。
查看文档和注释:glibc 的源码中包含了许多文档和注释,这些文档和注释可以帮助你更好地理解代码的实现原理和用途。
实践和调试:通过编写简单的程序来调用glibc 函数,并使用调试工具来跟踪程序的执行过程,可以帮助你更好地理解glibc 的实现原理和机制。
参与社区讨论:如果你在阅读过程中遇到问题或困难,可以参与glibc 的社区讨论,与其他开发者交流经验和心得。
Linux0.01_目录
目录名所属文件boot 核心引导代码fs 文件系统include 头文件init Init 进程,系统中执行的第一个进程kernel 系统调用lib 库代码mm 内存管理tools 内核引导文件的制作工具boot 目录文件描述boot.s BIOS 启动的时候加载并执行的代码head.s 32 bit 的引导代码,调用init_main()boot.s 文件说明加电自检结束后,boot.s 的代码被加载到0x7C00 处,然后boot.s 将自身移动到物理地址的0x90000 处,接着跳转到该处执行。
boot.s 使用BIOS 中断在屏幕上打印“/nLoading system.../n/n”接着读取核心镜像文件到0x100000 处,然后关闭引导设备,保存光标位置,关闭所有中断,再将系统核心从0x100000 复制到0x0000 处。
接着载入中断描述符表和全局描述符表。
head.s 文件说明该文件包含了32 位系统的初始化代码。
初始化代码的物理地址为:0x00000000 ,这个地址也是系统分页目录存放的地址。
因此,系统初始化完成后,系统初始化代码将被分页目录的数据替代。
head.s 的具体工作说明:setup_idt:建立一个256 个入口的中断向量表,并正确设置中断向量。
设置完中断向量后,打开中断。
setup_gdt:建立一个新的GDT,并正确设置表项。
在新的GDT 中,只有两个表项被装载,这两个表项是在init.s 中建立的。
setup_paging:通过cr0 标志位设置为0 来建立一个页表。
建立的页表可以映射机器的前8M 物理内存。
head.s 由boot.s 调用执行,当head.s 执行时,系统运行在32 位保护模式下。
当head.s 执行时,中断向量表与全局描述符表都已经被正确设置,并且合适的值被装入到CPU 的帧、栈、堆栈指针寄存器中,然后检查有没有浮点数处理单元,如果没有,就在中断向量表中设置一个软件异常处理程序,便于模式浮点数运算。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux 0.11文件系统的源码阅读总结1.minix文件系统对于linux 0.11内核的文件系统的开发,Linus主要参考了Andrew S.Tanenbaum 所写的《MINIX操作系统设计与实现》,使用的是其中的1.0版本的MINIX文件系统。
而高速缓冲区的工作原理参见M.J.Bach的《UNIX操作系统设计》第三章内容。
通过对源代码的分析,我们可以将minix文件系统分为四个部分,如下如1-1。
●高速缓冲区的管理程序。
主要实现了对硬盘等块设备进行数据高速存取的函数。
●文件系统的底层通用函数。
包括文件索引节点的管理、磁盘数据块的分配和释放以及文件名与i节点的转换算法。
●有关对文件中的数据进行读写操作的函数。
包括字符设备、块设备、管道、常规文件的读写操作,由read_write.c函数进行总调度。
●涉及到文件的系统调用接口的实现,这里主要涉及文件的打开、关闭、创建以及文件目录等系统调用,分布在namei和inode等文件中。
图1-1 文件系统四部分之间关系图1.1超级块首先我们了解一下MINIX文件系统的组成,主要包括六部分。
对于一个360K软盘,其各部分的分布如下图1-2所示:图 1-2 建有MINIX文件系统的一个360K软盘中文件系统各部分的布局示意图注释1:硬盘的一个扇区是512B,而文件系统的数据块正好是两个扇区。
注释2:引导块是计算机自动加电启动时可由ROM BIOS自动读入得执行代码和数据。
注释3:逻辑块一般是数据块的2幂次方倍数。
MINIX文件系统的逻辑块和数据块同等大小对于硬盘块设备,通常会划分几个分区,每个分区所存放的不同的文件系统。
硬盘的第一个扇区是主引导扇区,其中存放着硬盘引导程序和分区表信息。
分区表中得信息指明了硬盘上每个分区的类型、在硬盘中其实位置参数和结束位置参数以及占用的扇区总数。
其结构如下图1-3所示。
图1-3 硬盘设备上的分区和文件系统对于可以建立不同的多个文件系统的硬盘设备来说,minix文件系统引入超级块进行管理硬盘的文件系统结构信息。
其结构如下图1-4所示。
其中,s_ninodes表示设备上得i节点总数,s_nzones表示设备上的逻辑块为单位的总逻辑块数。
s_imap_blocks 和s_zmap_blocks分别表示i节点位图和逻辑块位图所占用的磁盘块数。
s_firstdatazone表示设备上数据区开始处占用的第一个逻辑块块号。
s_log_zone_size 是使用2为底的对数表示的每个逻辑块包含的磁盘块数。
对于MINIX1.0文件系统该值为0,因此其逻辑块的大小就等于磁盘块大小。
s_magic是文件系统魔幻数,用以指明文件系统的类型。
对于MINIX1.0文件系统,它的魔幻数是0x137f。
图 1-4 MINIX超级块结构对于超级块来说有两个特殊之处:●逻辑位图的最低比特位(位0)闲置不用,并在创建文件系统时会预先置1。
●I节点位图的最低比特位(位0)闲置不用,并在创建文件系统时会预先置1。
因此i节点位图只能表示8191个i节点的状况。
1.2 i节点I节点则是用来存放文件的相关信息。
对于每个文件或者目录名都有一个i节点,各自i节点结构中存放着对应文件的相关信息。
其i节点的结构(32个字节)如图1-6所示。
其中i_mode字段的是用来保存文件的类型和访问权限属性。
其15-12用于保存文件类型,为11-9保存执行文件时设置的信息,位8-0用于设置范文权限。
如图1-5所示。
I节点有一个特殊之处:●I节点0是闲置不用的,在文件系统创建时被置1。
图 1-5 i节点属性字段内容图 1-6 MINIX文件系统1.0版的i节点结构其中文件所占用得盘上逻辑块号数组结构如下图1-7所示。
图 1-7 i节点的逻辑块(区块)数组的功能1.3文件类型、属性和目录项Linux下文件属性的查看可以通过“ls –l”,具体如下图1-8所示:图 1-8 linux下“ls –l“显示的文件信息从上图可以看出来,在linux下通常可以分为六种类型的文件:●正规文件(‘-’),系统对其不做任何解释,包含有任何长度的字节流。
●目录(‘d’)在linux下也是一种文件,文件管理系统会对其内容进行解释。
●符号链接(‘s’)用于使用不同的文件名来引用另外一个文件。
分为软链接和硬链接。
软链接可以跨文件系统进行链接,删除时不会影响到源文件;而硬链接则不能跨文件系统(或者设备),它和被链接的文件地位相同,被作为一般文件对待,并且会递增文件的链接计数。
●命名管道(‘p’)文件时系统创建有名管道建立的文件,用于无关进程间的通信。
●字符设备(‘c’)文件用于以操作文件的方式访问字符设备。
主要包括tty终端、内存设备和网络设备。
●块设备(‘b’)文件用于访问硬盘、软盘等设备。
在linux下,块设备和字符设备文件一般存放在/dev目录下。
注释1:每个i节点都有一个链接计数i_nlinks,记录着指向该i节点的目录项数,这就是文件的硬链接计数。
在执行删除文件时,只有i_nlinks等于0时才允许删除此数据。
注释2:符号链接(即软链接)类型的文件并不会直接指向对应的文件的i节点,而是在其数据块中存储这一文件的路径名字符串,内核查看这个文件是通过路劲名进行直接解析的。
因此可以跨文件系统(或者设备)链接。
文件系统的目录项结构体定义在/include/linux/fs.h的头文件中,其结构如下图1-9所示。
图 1-9 目录项结构体的定义注释1:一个逻辑块能存储的目录项1024/16=64注释2:对于i节点的i_zone[0]所对应的逻辑块来说,它在初始化时首先存储了“.”(自己目录的i节点号)和“..”(父目录的i节点号)两个目录,在代码中会有体现,对目录项进行遍历时,会从2开始。
通过文件名从文件系统中获取其数据块的流程图如下图1-10所示。
图 1-10 以文件名获取其数据块1.4高速缓冲区高速缓冲区是文件系统访问块设备中数据的必经之道,它的主要作用如下:●将磁盘块中的数据预读到缓冲区,减少对磁盘的频繁访问,提高系统性能。
●当需要将数据写入到块设备时,则先将数据转存在高速缓冲区中,然后由高速缓冲区通过设备数据同步来实现写入块设备。
高速缓冲存放着最近使用过得各个块设备中的数据块。
当需要从块设备中读取数据时,缓冲管理程序首先会再高速缓冲中寻找数据。
如果在缓冲区,则直接返回数据块的指针,反之,则发出读设备的命令,将磁盘块中得数据读入高数缓冲区。
如下图1-11所示,显示了高速缓冲区位于内核模块和主内存区之间。
图 1-11 高速缓冲区在整个内存中的位置注释1:end是内核模块链接期间由链接程序ld设置的一个外部变量,内核代码中没有定义这个符号。
当在连接生成system模块时,ld程序设置了end的地址,它等于data_start+datasize+bss_size,即bss段结束后的第一个有效地址。
注释2:高速缓冲区被划分为1024字节大小的缓冲块,正好与块设备上的磁盘逻辑块大小相同。
高速缓冲区从物理角度看主要由缓冲块和指向缓冲块的缓冲头组成。
其中缓冲头的结构体为:struct buffer_head {char * b_data; //指向该缓冲块中数据区(1024字节)的指针unsigned long b_blocknr; //块号unsigned short b_dev; //数据块的设备号unsigned char b_uptodate; //更新标志,表示设备是否更新unsigned char b_dirt; //修改标志,0-未修改,1-已修改unsigned char b_count; //使用该块的用户数,用于清除数据块时。
unsigned char b_lock; //缓冲区上所标识,0-ok,1-lockedstruct task_struct * b_wait; //指向等待使用此缓冲块的进程struct buffer_head * b_prev; //hash队列上一块struct buffer_head * b_next; //hash队列下一块struct buffer_head * b_prev_free; //空闲表上一块struct buffer_head * b_next_free; //空闲表下一块};注释1:字段b_dirt是脏标志,说明该缓冲块中得内容是否已修改而与块设备上得对应数据块内容不同(延迟写)。
B_uptodate是数据更新标志,说明缓冲块中数据是否有效。
初始化或者释放块时这两个标志设置为0,表示该缓冲块此时无效。
注释2:b_dirt=1,b_uptodate=0,数据被写入缓冲块但是还没有被写入设备;b_dirt=0,b_uptodate=1,数据被写入了设备块或者刚从设备快中读入缓冲块中变成有效;b_dirt=1,b_uptodate=1,表示缓冲块和设备快上得数据不同,但是数据还是有效的(更新的)。
高速缓冲区采用hash表和空闲缓冲块队列进行操作管理,这也是高速缓冲区从逻辑上的组成。
在缓冲区初始化过程中,初始化程序从整个缓冲区的两端开始,分别同时设置缓冲头块和划分对应的缓冲块,如图1-12所示。
缓冲头的结构体描述了对应缓冲块的属性,并且用于把所有的缓冲头连接成一个双向链表结构。
如图1-13所示。
图 1-12 高速缓冲区的初始化示意图注释1:高端建立了1024大小的缓冲块,低端建立了对应的缓冲块头图 1-13 所有缓冲块组成的双向循环链表结构注释1:free_list指针是该链表的头指针,指向空闲块链表中第一个“最为空闲的”缓冲块,即近期最少使用的块。
为了能够快速而有效地在缓冲区中寻找判断出请求的数据块是否已经被读入缓冲区中,buffer.c使用了具有307个buffer_head指针项的hash数组结构。
Hash函数采用了设备号和逻辑块号作为参数,具体函数:(设备号^逻辑块号)Mod307。
然后通过b_prev、p_next将hash表中散列在同一项上的多个缓冲块练成一个双向链表。
通过hash数组实现管理缓冲块的好处是保证了同一设备号的块具有相同的散列值,加速对缓冲区中得块的查询。
图1-14所示为某一时刻内核中缓冲块散列队列示意图。
图1-14 某一刻内核中缓冲块散列队列示意图2源码分析这一部分主要从源码fs/目录下的各个文件进行逐个分析,理清它们之间的调用关系,并通过流程图的形式展现其中关键代码的实现。
本章可以划分为五大部分:1)高速缓冲管理;2)文件底层操作;3)文件数据访问;4)文件高层访问控制;5)文件系统的初始化和define变量说明。
2.1高速缓冲管理高速缓冲管理在fs/buffer.c中得到实现。