linux内核 订阅
Linux是一种开源电脑操作系统内核。它是一个用C语言写成,符合POSIX标准的类Unix操作系统。 [1]  Linux最早是由芬兰 Linus Torvalds为尝试在英特尔x86架构上提供自由的类Unix操作系统而开发的。该计划开始于1991年,在计划的早期有一些Minix 黑客提供了协助,而今天全球无数程序员正在为该计划无偿提供帮助。 展开全文
Linux是一种开源电脑操作系统内核。它是一个用C语言写成,符合POSIX标准的类Unix操作系统。 [1]  Linux最早是由芬兰 Linus Torvalds为尝试在英特尔x86架构上提供自由的类Unix操作系统而开发的。该计划开始于1991年,在计划的早期有一些Minix 黑客提供了协助,而今天全球无数程序员正在为该计划无偿提供帮助。
信息
软件授权
免费
软件名称
Linux内核
发明者
Linus Torvalds
使用时间
1991年
软件语言
C语言
Linux内核内核结构
操作系统是一个用来和硬件打交道并为用户程序提供一个有限服务集的低级支撑软件。一个计算机系统是一个硬件和软件的共生体,它们互相依赖,不可分割。计算机的硬件,含有外围设备、处理器、内存、硬盘和其他的电子设备组成计算机的发动机。但是没有软件来操作和控制它,自身是不能工作的。完成这个控制工作的软件就称为操作系统,在Linux的术语中被称为“内核”,也可以称为“核心”。Linux内核的主要模块(或组件)分以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信,以及系统的初始化(引导)、系统调用等。Linux内核使用三种不同的版本编号方式。  第一种方式用于1.0版本之前(包括1.0)。第一个版本是0.01,紧接着是0.02、0.03、0.10、0.11、0.12、0.95、0.96、0.97、0.98、0.99和之后的1.0。第二种方式用于1.0之后到2.6,数字由三部分“A.B.C”,A代表主版本号,B代表次主版本号,C代表较小的末版本号。只有在内核发生很大变化时(历史上只发生过两次,1994年的1.0,1996年的2.0),A才变化。可以通过数字B来判断Linux是否稳定,偶数的B代表稳定版,奇数的B代表开发版。C代表一些bug修复,安全更新,新特性和驱动的次数。以版本2.4.0为例,2代表主版本号,4代表次版本号,0代表改动较小的末版本号。在版本号中,序号的第二位为偶数的版本表明这是一个可以使用的稳定版本,如2.2.5,而序号的第二位为奇数的版本一般有一些新的东西加入,是个不一定很稳定的测试版本,如2.3.1。这样稳定版本来源于上一个测试版升级版本号,而一个稳定版本发展到完全成熟后就不再发展。第三种方式从2004年2.6.0版本开始,使用一种“time-based”的方式。3.0版本之前,是一种“A.B.C.D”的格式。七年里,前两个数字A.B即“2.6”保持不变,C随着新版本的发布而增加,D代表一些bug修复,安全更新,添加新特性和驱动的次数。3.0版本之后是“A.B.C”格式,B随着新版本的发布而增加,C代表一些bug修复,安全更新,新特性和驱动的次数。第三种方式中不再使用偶数代表稳定版,奇数代表开发版这样的命名方式。举个例子:3.7.0代表的不是开发版,而是稳定版!Linux最早是由芬兰人Linus Torvalds设计的。当时由于UNⅨ的 商业化,Andrew Tannebaum教授开发了Minix操作系统以便于不受AT&T许可协议的约束,为教学科研提供一个操作系统。当时发布在Internet上,免费给全世界的学生使用。Minix具有较多UNⅨ的特点,但与UNⅨ不完全兼容。1991年10月5日,Linus为了给Minix用户设计一个比较有效的UNⅨ PC版本,自己动手写了一个“类Minix”的操作系统。整个故事从两个在终端上打印AAAA...和BBBB...的进程开始的,当时最初的内核版本是0.02。Linus Torvalds将它发到了Minix新闻组,很快就得到了反应。Linus Torvalds在这种简单的任务切换机制上进行扩展,并在很多热心支持者的帮助下开发和推出了Linux的第一个稳定的工作版本。1991年11月,Linux0.10版本推出,0.11版本随后在1991年12月推出,当时将它发布在Internet上,免费供人们使用。当Linux非常接近于一种可靠的/稳定的系统时,Linus决定将0.13版本称为0.95版本。1994年3月,正式的Linux 1.0出现了,这差不多是一种正式的独立宣言。截至那时为止,它的用户基数已经发展得很大,而且Linux的核心开发队伍也建立起来了。在讨论大型而复杂的系统的体系结构时,可以从很多角度来审视系统。体系结构分析的一个目标是提供一种方法更好地理解源代码。Linux 内核实现了很多重要的体系结构属性。在或高或低的层次上,内核被划分为多个子系统。Linux 也可以看作是一个整体,因为它会将所有这些基本服务都集成到内核中。这与微内核的体系结构不同,后者会提供一些基本的服务,例如通信、I/O、内存和进程管理,更具体的服务都是插入到微内核层中的。随着时间的流逝,Linux 内核在内存和 CPU 使用方面具有较高的效率,并且非常稳定。但是对于 Linux 来说,最为有趣的是在这种大小和复杂性的前提下,依然具有良好的可移植性。Linux 编译后可在大量处理器和具有不同体系结构约束和需求的平台上运行。一个例子是 Linux 可以在一个具有内存管理单元(MMU)的处理器上运行,也可以在那些不提供MMU的处理器上运行。Linux 内核的uClinux移植提供了对非 MMU 的支持。核心的开发和规范一直是由Linux社区控制着,版本也是唯一的。实际上,操作系统的内核版本指的是在Linus本人领导下的开发小组开发出的系统内核的版本号。自1994年3月14日发布了第一个正式版本Linux 1.0以来,每隔一段时间就有新的版本或其修订版公布。Linux将标准的GNU许可协议改称Copyleft,以便与Copyright相对照。通用的公共许可(GPL)允许用户销售、拷贝和改变具有Copyleft的应用程序。当然这些程序也可以是Copyright的,但是你必须允许进一步的销售、拷贝和对其代码进行改变,同时也必须使他人可以免费得到修改后的源代码。事实证明,GPL对于Linux的成功起到了极大的作用。它启动了一个十分繁荣的商用Linux阶段,还为编程人员提供了一种凝聚力,诱使大家加入这个充满了慈善精神的Linux运动。
收起全文
精华内容
参与话题
问答
  • Linux内核简介

    万次阅读 多人点赞 2018-06-16 18:56:29
    大纲:理解Linux内核最好预备的知识点Linux内核的特点Linux内核的任务内核的组成部分哪些地方用到了内核机制?Linux进程 Linux创建新进程的机制Linux线程 内核线程地址空间与特权级别 虚拟地址与物理地址 特权级别...

    大纲:

    理解Linux内核最好预备的知识点
    Linux内核的特点
    Linux内核的任务
    内核的组成部分
    哪些地方用到了内核机制?
    Linux进程
    Linux创建新进程的机制
    Linux线程
    内核线程
    地址空间与特权级别
            虚拟地址与物理地址
            特权级别(Linux的两种状态)
            系统调用
    设备驱动程序、块设备和字符设备
    网络
    文件系统

    模块和热插拔

    注:本文为《深入Linux内核架构》 的学习笔记


    理解Linux内核最好预备的知识点:

    • 懂C语言
    • 懂一点操作系统的知识
    • 熟悉少量相关算法
    • 懂计算机体系结构


    Linux内核的特点:

    结合了unix操作系统的一些基础概念


    Linux内核的任务:

    1.从技术层面讲,内核是硬件与软件之间的一个中间层。作用是将应用层序的请求传递给硬件,并充当底层驱动程序,对系统中的各种设备和组件进行寻址。
    2.从应用程序的层面讲,应用程序与硬件没有联系,只与内核有联系,内核是应用程序知道的层次中的最底层。在实际工作中内核抽象了相关细节。
    3.内核是一个资源管理程序。负责将可用的共享资源(CPU时间、磁盘空间、网络连接等)分配得到各个系统进程。

    4.内核就像一个库,提供了一组面向系统的命令。系统调用对于应用程序来说,就像调用普通函数一样。


    内核实现策略:

    1.微内核。最基本的功能由中央内核(微内核)实现。所有其他的功能都委托给一些独立进程,这些进程通过明确定义的通信接口与中心内核通信。

    2.宏内核。内核的所有代码,包括子系统(如内存管理、文件管理、设备驱动程序)都打包到一个文件中。内核中的每一个函数都可以访问到内核中所有其他部分。目前支持模块的动态装卸(裁剪)。Linux内核就是基于这个策略实现的。


    内核的组成部分:

    1.用户空间(在“地址空间与特权级别”小节会详细介绍):
    应用程序:
    C库


    2.内核空间(在“地址空间与特权级别”小节会详细介绍):
    核心内核
    设备驱动程序

    硬件

    详细可参考图1


    图1 Linux内核组成部分


    哪些地方用到了内核机制?

    1.进程(在cpu的虚拟内存中分配地址空间,各个进程的地址空间完全独立;同时执行的进程数最多不超过cpu数目)之间进行通   信,需要使用特定的内核机制。
    2.进程间切换(同时执行的进程数最多不超过cpu数目),也需要用到内核机制。
        进程切换也需要像FreeRTOS任务切换一样保存状态,并将进程置于闲置状态/恢复状态。

    3.进程的调度。确认哪个进程运行多长的时间。


    Linux进程

    1.采用层次结构,每个进程都依赖于一个父进程。内核启动init程序作为第一个进程。该进程负责进一步的系统初始化操作。init进程是进程树的根,所有的进程都直接或者间接起源于该进程。
    2.通过pstree命令查询。实际上得系统第一个进程是systemd,而不是init(这也是疑问点)

    3.系统中每一个进程都有一个唯一标识符(ID),用户(或其他进程)可以使用ID来访问进程。

    • Linux创建新进程的机制;
            1.使用fork函数。
    功能:创建当前进程的一个副本。父进程和子进程只有PID(进程ID)不同。父进程的内容被复制。(写时复制:可以了解下这个概念)


            2.使用exec函数。

    功能:将一个新程序加载到当前进程的内存中并执行。旧程序的内存页将刷出,其内容替换为新的数据。然后开始执行新程序。


    Linux线程

    进程可以看成是一个正在执行的程序,而线程则是与主程序并行运行的程序函数或例程。

    • Linux创建新线程 

            采用clone方法创建线程。

    • 内核线程
            特点:
    1.不与任何特定的用户空间进程相关联。
    2.与中断上下文运转的内核相比,内核线程可以进入睡眠状态,也可以像系统中的普通进程一样被调度器跟踪。

    用途:
    1.从内存和块设备之间的数据同步。
    2.帮助调度器在CPU上分配进程。

    如何查看内核线程:
    命令:ps fax   方括号内的就是内核线程。


    地址空间与特权级别

    在正式介绍之前先介绍几个单位:

    KiB  2^10字节
    MiB  2^20

    GiB  2^30

    • 地址空间

        虚拟地址与物理地址:

            虚拟地址:在计算机的专用术语中是指标识一个虚拟(非物理地址)的实体地址。

            物理地址:切切实实存在的地址。在存储器里以字节为单位存储信息,为正确地存放或取得信息,每一个字节单元给以一个唯一的存储器地址,称为物理地址。

            映射关系:
                用页表为物理地址分配虚拟地址
        注意:未必虚拟地址的所有页都映射到某个页帧。
        原因:
    1.页没有内存可以使用
    2.数据尚不需要使用而没有载入内存。
    3.页已经换出硬盘,需要时再换回内存。


        页帧:物理内存页
        页:专指虚拟地址空间中的页。
        页表:将虚拟地址空间映射到物理地址空间的数据结构。
        多级分页:建立虚拟地址到物理地址映射的一种方法,能有效减少内存用量。


        CPU加速内存的访问过程,方法:
        1.MMU(Memory Management Unit)内存管理单元
        2.TLB(Translation Lookaside Buffer)地址转换后备缓冲器

        IA-32位结构的CPU只需要使用二级页表,Linux内核总是使用四级页表,剩余部分由内核通过控页表对缺少的页表进行仿真。

        概念注意:

        1.CPU的字长决定了所能管理的地址空间的最大长度。对于32位系统是2^32 B = 4GiB
        2.虚拟地址空间:地址空间的最大长度与实际可用的物理内存的数量无关。
    虚拟地址空间划分为两个部分:
    内核空间

    用户空间

                    如图2所示:


    图2 虚拟内存的划分

            有个等价名称值得一提:
    用户层:指应用程序本身。指不属于内核的东西。
    用户空间:不仅可以表示应用程序,还指代应用程序所运行的虚拟地址空间的一部分。与内核空间相对。

    注意:每一个进程都有上述独立的虚拟地址空间。对于图2所示,每个进程有4GiB的内存空间。

    • 特权级别
            Linux有两种状态,两种状态代表两种特权级别:
           核心态:在虚拟地址的内核空间运行的状态。
           用户状态:在虚拟地址的用户空间运行的状态。
        注意:在用户状态禁止访问内核空间


            这两种状态的差别在于:对高于TASK_SIZE的内存区域的访问。

    • 系统调用
            定义:从用户状态到核心态的切换通过系统调用的特定手段完成。
    方法:
    1.内核代表用户程序执行代码
    2.异步硬件中断激活,然后在中断上下文中进行。注意:在中断上下文运行时,内核不能进入睡眠状态。
            注意:

    CPU大多数在执行用户空间中的代码。当应用程序执行系统调用时,则会切换到核心态,内核将完成其请求。在此期间,内核可以访问虚拟地址空间的用户部分。在系统调用完成之后,CPU切换回用户状态。 

            硬件中断也使CPU切换到核心态,但这种情况下内核不能访问用户空间。

            系统调用有哪些:

                    进程管理
    信号
    文件
    目录和文件系统
    保护机制
    定时器函数

    如:在IA-32处理器上,Linux使用一个专用软件中断执行系统调用。

    设备驱动程序、块设备和字符设备
    设备驱动程序的任务:是在于支持应用程序经由设备文件与设备通信。换言之,使得能按恰当的方式在设备上读取/写入数据。
    设备驱动程序的定义:用于与系统连接的输入/输出装置通信。如硬盘、软驱、各种接口、声卡等。


    外设分为两类:
    1.字符设备。提供连续的数据流,数据可以顺序读取,通常不支持随机存取。支持按字节/字符来读写数据。
    典型:调制解调器
    2.块设备。可以随机访问设备数据,程序可以自行确定读取数据的位置。不支持基于字符寻址,数据读写只能以块的倍数进行。
    典型:硬盘。
    复杂性:比字符设备复杂,因为设计到缓存机制。


    网络
    网卡也可以通过设备驱动程序控制。
    但在内核中,网卡不能以设备文件访问。因为网络通信期间数据打包到各种协议层,内存处理数据必须针对协议层处理,才能有效将数据对接应用程序。
            为了支持用文件接口处理网络连接。Linux提供了套接字抽象,套接字可以看成是应用程序、文件接口、内核的网络实现之间的代理。


    文件系统
    文件存储在硬盘或者其他块设备(如光盘等),采用层次式文件系统。
    文件系统使用目录结构主治存储的数据,并将其他原信息(如所有者、访问权限等)关联起来。


    Linux支持许多不同的文件系统:
    如标准的Ext2和Ext3文件系统、ReiserFS、XFS、VFAT等

    注意:软件层(Virtual Filesystem虚拟文件系统)内核必须提供一个额外的软件层,将各种底层的文件系统的具体特征与应用层隔离开。如图3所示。


    图3 文件系统的额外软件层

    参考文献:

    [1]Wolfgang Mauerer.《深入Linux内核架构》 Wolfgang Mauerer著 郭旭译 人民邮电出版社


    展开全文
  • 深入理解Linux内核(完整版)-笔记

    万次阅读 2018-05-17 08:32:16
    第一章、绪论 1.Unix文件可以是下列类型之一: a.正规文件(regular file) b.目录(directroy) c.符号链(symbolic link) d.块设备文件(block-oriented device file) e.字符设备文件(charactor-oriented ... f....
    第一章、绪论
    	1.Unix文件可以是下列类型之一:
    		a.正规文件(regular file)
    		b.目录(directroy)
    		c.符号链(symbolic link)
    		d.块设备文件(block-oriented device file)
    		e.字符设备文件(charactor-oriented device file)
    		f.管道(pipe)命名管道(named pipe)(即FIFO)
    		h.套接字(socket)
    
    	2.内核分配给进程的虚拟地址空间由以下内存区域组成:
    		a.程序的可执行代码
    		b.程序的初始化数据
    		c.程序的未初始化数据
    		d.初始程序栈(即用户态栈)
    		e.需要共享的库的可执行代码和数据
    		f.堆(由程序动态请求的内存)
    	
    	3.设备驱动程序
    		内核通过设备驱动程序(device driver)与I/O设备打交道。设备驱动程序包含在内核中,由控制一个或多个设备的数据结构和函数组成。
    		这些设备包括硬盘、键盘、鼠标和监视器等。通过特定的接口,每个驱动程序与内核中的其余部分(甚至与其他驱动程序)相互作用:
    		优点:
    			1.可以把特定设备的代码封装在特定的模块中。
    			2.厂商可以不懂内核代码,只知道接口规范,就能增加新的设备。
    			3.内核以统一的方式对待所有的设备,并且通过相同的接口访问这些设备。
    			4.可以把设备驱动程序写成模块,并动态装到内核中,不需要重启系统,不需要的时候可以卸载模块,
    				以减少存储在RAM中的内核映像大小。
    
    第三章、进程				
    	1.进程状态:
    		a.可运行状态
    		b.可中断状态
    		c.不可中断的等待状态
    		d.暂停状态
    		e.僵死状态
    
    第十章、进程调度		
    	1.涉及进程调度
    		a.传统上把进程分类:
    			I/O范围(I/O-bound):频繁地使用I/O设备,并花费很多时间等待I/O操作的完成。
    			CPU范围(CPU-bound):需要大量CPU时间的数值计算应用程序。
    			
    		b.非传统分类:
    			交互式进程:如命令shell、文本编辑程序及图像应用程序。
    			批处理进程:如编译程序、数据库搜索引擎及科学计算。
    			实时进程:视频和音频应用程序、机器人控制程序及从物理传感器上收集数据的程序。
    		
    第十一章、内核同步	
    	1.内核同步,内核态进程的非抢占性:
    		a.在内核态中运行的进程不会被其他进程取代,除非这个进程主动放弃CPU的控制权
    		b.中断或异常处理可以中断在内核态中运行的进程。但是,在中断处理程序结束时,该进程的内核控制路径被恢复
    		c.执行中断或异常处理的内核控制路径只能被执行中断或异常处理的其他内核控制路径所中断
    
    	2.SMP原子操作 从Intel 80286开始引入lock指令解决这中问题。
    		lock只是一个用于一条汇编指令之前的特殊字节。当控制单元检测到一个lock字节时,就锁定内存总线
    		这样其他处理器就不能存取下一条汇编语言指令的目的操作数所指定的内存单元。只有在这条指令执行完成时总线锁才会被释放。
    		因此,带有lock前缀的读-修改-写指令即使在多处理器环境中也是原子的。
    			
    	3.内核数据结构进行同步访问的常用方法是使用信号量和自旋锁。
    		
    第十二章、虚拟文件系统
    	1.通用文件模型由下列对象类型组成:
    		a.超级块对象(superblock object):存放已安装文件系统的有关信息。对于基于磁盘的文件系统,
    			这类对象通常对应于存放在磁盘上的文件系统控制块(filesystem control block)。
    		b.索引节点对象(inode object):存放关于具体文件的一般信息。对于基于磁盘的文件系统,
    		  这类对象通常对应于存放在磁盘上的文件控制块(file control block)。
    			每个索引节点对象都有一个索引节点号,这个号唯一地标识文件系统中的指定文件。
    		c.文件对象(file object):存放打开文件与进程之间交互的相关信息。这类信息仅当进程访问文件期间存在于内核内存中。
    		d.目录项对象(dentry object):存放目录项与对应文件进行连接的信息。每个基于磁盘的文件系统都以自己特有的方式将该类信息存在磁盘上。
    			slab分配高速缓存中。
    		e.进程->文件对象->目录项对象->索引节点->(超级块对象)->磁盘文件。
    		
    	2.虚拟文件系统,目录项对象属于以下四种状态之一:
    		a.空闲状态:		还没有被VFS使用,对于德内存区由slab分配器进行管理。
    		b.未使用状态:		该目录项对象当前还没有被内核使用。该对象的引用计数器d_count为NULL。
    			但其d_indoe域只想相关索引节点。为了必要时回收内存,目录项包含有效信息,它的内存可能被丢失。
    		c.正在使用状态:	该对象被内核使用。d_count的值为正数。目录项包含有效的信息,并且不能被丢弃。
    		d.负状态:			与目录项相关的索引节点不复存在,那是因为相应的磁盘索引节点已被删除,d_count域被置NULL。
    	
    第十三章、管理I/O设备
    	1.三类内存地址:
    		a.逻辑地址(CPU内部使用)
    		b.线性地址(CPU内部使用)
    		c.物理地址(CPU从物理上驱动数据总线所用的内存地址)
    		d.总线地址(bus address):除CPU之外的硬件设备驱动数据总线所用的内存地址。
    		
    	2.设备文件(mknod()系统调用来创建设备文件):用来表示Linux所支持的大部分I/O设备的,除了文件名,每个设备文件都还有三个主要属性。
    		a.类型(type):块设备或字符设备
    		b.主号(major number):从1到255之间的一个数,用以标识设备的类型,通常,具有相同主号和相同类型的所有设备文件共享相同的文件操作集合。
    			因为他们是由同一设备驱动程序处理的。
    		c.次号(minor number):在一组主号相同的设备之间唯一标识特定设备所使用的一个数字。
    	
    	3.没有对应设备文件的I/O设备
    		比如网卡:网卡把向外发送的数据放入通往远程计算机系统的一条线上,把从远程系统中接受到的报文装入内核内存。
    				 由于没有使用文件系统,所以系统管理员必须建立设备名和网络地址之间的联系。
    				 应用程序和网络接口之间的数据通信不是基于标准的有关文件的系统调用。
                                     而是基于socket()、bind()、listen()、accept()和connect()系统调用。
    				 这些系统调用对网络地址进行操作。这组系统调用由Unix BSD中首先引入,现在已经成为网络设备的标准变成模型。
    				 
    	4.VFS对设备文件的处理:设备文件也在系统的目录数中。但它们和正规文件及目录有根本的不同。当进程访问正规文件时,
               它会通过文件系统访问磁盘分区的一些
    		数据块;而在进程访问设备文件时,它只要驱动硬件设备就可以了。VFS的责任是为应用程序隐藏设备文件与正规文件之间的差异。
    		VFS改变打开的设备文件的缺省文件操作。可以把对设备文件的任一系统调用转换成对设备相关的函数的调用,而不是对主文件系统对于函数的调用。
    		设备相关的函数对硬件设备进行操作以完成进程所请求的操作。
    		
    		驱动程序:控制I/O设备的一组相关的函数称为设备驱动程序(device driver)。由于每个设备都有一个唯一的I/O控制器,因此也就有唯一的
    				 命令和唯一的状态信息,所以大部分I/O设备类型都有自己的驱动程序。
    	
    	5.设备文件调用open()函数执行的操作:
    		a.如果设备驱动程序被包含在一个内核模块中,那么把引用计数器的值加1,以便只有把设备文件关闭之后才能卸载这个模块。
    		b.如果设备驱动程序要处理多个同类型的设备,那么就是用次号来选择合适的驱动程序,如果需要,还要使用专门的文件操作表选择驱动程序。
    		c.检查该设备是否真正存在,现在是否正在工作。
    		d.如果必要,向硬件设备发送一个初始化命令序列。
    		e.初始化设备驱动程序的数据结构。
    				 
    	6.内核支持的级别
    		a.根本不支持:应用程序使用设当的in和out汇编语言指令直接与设备的I/O端口进行交互。
    		b.最小支持:内核不能设别硬件设备,但能识别I/O接口。用户程序把I/O接口是为能够读写字符流的顺序设备。
    		c.扩展支持:内核设备硬件设备,并处理I/O设备本身,事实上,这种设备可能就没有对应的设备文件。
    	
    	7.访问I/O设备的地址,可以从/proc/ioports文件中获得。
    	
    	8.内核对于块设备的支持特点:
    		a.通过VFS提供统一接口
    		b.对磁盘数据进行有效的链接
    		c.为数据提供磁盘高速缓存
    		
    	9.内核基本上把I/O数据传送划分成两类:
    		a.缓冲区I/O操作:所传送的数据保存在缓冲区中,缓冲区是磁盘数据在内核中的普通内存容器。每个缓冲区都和一个特定的块相关联
    		  而这个块由一个设备号和一个块号来标识
    		b.页I/O操作:所传输的数据保存在页框中,每个页框包含的数据都属于正规文件。因为没有必要把这种数据存放在相邻的磁盘中。
    		  所以就是用文件的索引节点和文件内的偏移量来标识这种数据。主要用于读取正规文件、文件内存映射和交换。
    		  
    	10.所谓块(block):就是块设备驱动程序在一次单独操作中所传送的一大块相邻字节。
    	   扇区(sector):扇区是硬件设备传送数据的基本单元。
    	   
    	11.块设备驱动程序的两部分:
    		a.高级驱动程序:处理VFS层。
    		b.低级驱动程序:处理硬件设备。
    		  
    第十五章、访问正规文件
    	1.从正规文件读取数据:generic_file_read()函数实现了大部分文件系统的正规文件的read方法。
    	2.对正规文件进行预读:正规文件的预读需要的算法比物理块的预读需要的算法更复杂:
    		a.由于数据是逐页进行读取的,因此预读算法不必考虑页内偏移量,只考虑所访问的页在文件内部的位置就可以了。
    		b.当前访问与上一次访问不是顺序的时,预读就必须从头开始重新执行。
    		c.当进程一直反复地访问同一页时(该文件只有很少的一部分被使用),应该减慢预读的速度甚至停止执行。
    		d.如果需要,预读算法必须激活低级I/O设备驱动程序来确保新页会被读取。
    		e.内核通过多次调用一个名为:try_to_read_ahead()的函数来执行预读操作(read ahead operation),一次预读一页。
    		f.对于每个请求页,内核都要调用generic_file_readhead()函数,该函数确定是否要执行预读操作。
    		
    	3.写正规文件:write()系统调用会涉及把数据从调用进程的用户态地址空间中移动到内核数据结构中,然后再移动到磁盘上。
    				 文件对象的write方法允许每种文件类型都定义一个专用的写操作。
    		a.写操作发生时,有效数据是在缓冲区高速缓存中,而不是在页高速缓存中,更确切地说,当write方法修改了文件的任何部分时。
    		  与这些部分对应的页高速缓存中的所有页都不再包含有效数据。一个进程可能认为自己在读取正确数据,
                     但是却没看到其他进程对这些数据所做的修改。
    		b.所有基于磁盘的文件系统的write方法都要调用update_vm_cache()函数来修改读操作所使用的页高速缓存。
    		c.通过页高速缓存对正规文件执行的写操作,只能用于网络文件系统。文件的write方法是使用generic_file_write()函数实现。
    		
    	4.内存映射:一个线性区可以和基于磁盘的文件系统中的一个文件(或者文件的一部分)相关联。这就是说,内核会把线性区中对一个页中字节的访问转换成
    			   对正规文件中相对于字节的操作,这种技术成为内存映射。
    		a.共享的:对线性区中的任何写操作都会修改磁盘上的文件。而且,如果进程对共享内存映射中的一个页进行写,
                       那么这种修改对于其他映射了相同文件的所有
    				进程来说都是可见的。
    		b.私有的:当进程创建的映射只是为读文件,而不是写文件时才会使用。处于这种目的,私有映射的效率要比共享映射的效率更高。
    		    但是私有映射页的认识写操作都会使内核不再映射该文件中的页。一个写操作即不会改磁盘上的文件,
                        对访问相同文件的其他进程来说这种改变也是不可见的。
    		c.使用mmap()系统调用创建一个新的内存映射。必须指定MAP_SHARED或MAP_PRIVATE标志。
    		
    第十六章、磁盘数据结构
    	1.任何Ext2分区中的第一个块从不受Ext2文件系统的管理,因为这一块是为启动扇区所保留的。Ext2分区的其余部分被分成块组(block group)。
    	2.块组中的每个块包含下列信息之一:
    		a.一个Ext2文件系统超级块的拷贝
    		b.一组块组描述符的拷贝
    		c.一个数据块位图:标识在一组中块的使用和空闲状况。
    		d.一个索引节点位图
    		e.一组索引节点
    		f.属于文件的一块数据;即一个数据块。
    	3.如果一个块中不包含任何有意义的信息,就说这个块是空的。
    	4.在Ext2文件系统中的所有块组大小相同并被顺序存放,因此,内核可以从块组的整数索引很容易地得到磁盘中一个块组的位置。
    	5.超级块与组描述符被复制到每个块组中。只有块组0中所包含的超级块和描述符才由内核使用,而其余的超级块和组描述符保持不变
    	  事实上,内核甚至不考虑它们。
    	6./sbin/e2fsck程序对Ext2文件系统的状态执行一致性检查时,就引用存放在块组0中的超级块和组描述符,然后把它们拷贝到其他所有的块组中。
    	7.每组之多有8 x b块,b是以字节单位的块大小。
    	8.示例:
    		8GB的Ext2分区
    		块的大小为4KB
    		块位图的大小4KB(b=4KB)
    		最多描述32KB的数据块
    		每个块组的容量:4KB x 32KB = 128MB
    		最多需要的块组数: n = 8GB/128MB = 64
    	9.磁盘数据结构:
    		a.超级块的域:
    			索引节点的总数
    			以块位单位的文件系统的大小
    			保留的块数
    			空闲块计数器
    			空闲索引节点计数器
    			第一次使用的块号(总为1)
    			块的大小
    			片的大小
    			每组中的块数
    			每组中的片数
    			.....
    		b.组描述符:每个块组有自己的组描述符,为ext2_group_desc结构。
    			Ext2组描述符的域
    				块位图的块号
    				索引节点位图的块号
    				第一个索引节点表块的块号
    				组中空闲块的个数
    				组中索引节点的个数
    			组中目录的个数
    			.....
    		c.位图:是位的序列,0表示相应的索引节点块或数据块是空闲的,1表示占用。
    		d.索引节点表:所有索引节点的大小相同,即128字节。索引节点表第一个块的块号存放在组描述符的bg_inode_table域中。
    			Ext2磁盘索引节点的域:
    				文件类型和访问权限
    				拥有者的标识符
    				以字节为单位的文件长度
    				最后一次文件访问的时间
    				.......
    			文件的索引节点号没有必要再磁盘上存放,因为它的值可以从块组号和它在索引节点表中的相对于位置而得出。
    	10.Ext2的文件操作:
    		VFS方法的read和mmap是由很多文件系统共用的通用函数实现的。这些方法存放在
    		ext2_file_operations表中:
    			lseek -> ext2_file_lseek()
    			read  -> generic_file_read()
    			write -> ext2_file_write()
    			.......
    			
    	11.各种文件类型如何使用磁盘块
    		正规文件:正规文件只有在开始有数据时才需要数据块。
    		目录:Ext2以一种特殊的文件实现了目录,这种文件的数据块存放了文件名和相应的所有节点号。
    			 数据块中包含了类型为ext2_dir_entry_2的结构
    			 名字域最大为EXT2_NAME_LEN(通常是255)个字符的边长数组。
    			 目录项的长度是4的倍数
    		符号链:符号链的路径名达到60个字符,就把它存放在索引节点的i_blocks域,该域是由15个4字节整数组成的数组,因此无需数据块
    			    如果路径名大于60个字符,就需要一个单独的数据块。
    		设备文件、管道和套接字:这些类型的文件不需要数据块,所有必须的信息都存放在索引节点中。
    		
    	12.Ext2文件的类型
    		0 未知
    		1 正规文件
    		2 目录
    		3 字符设备
    		4 块设备
    		5 命名管道
    		6 套接字
    		7 符号链
    		
    	13.文件的洞是正规文件的一部分,它是一些空字符但没有存放在磁盘的任何数据块中。
    	    引入文件的洞是为了避免磁盘空间的浪费。它们被广泛地用在数据库引用中,更一般的说,用于文件上散列法的所有应用。
    第十八章 进程通信
    	1.进程间通信的机制:
    		管道和FIFO(管道):最适合在进程之间实现生产者/消费者的交互。有些进程往管道中写入数据,而另外一些进程则从管道中读取数据。
    			无名管道:用户无法打开一个现有的管道。除非管道是由一个公共的祖先进程创建的。
    			有名管道:有磁盘索引节点,因此任何进程都可以访问FIFO,没有使用数据块,使用内核缓冲区。
    		信号量IPC(Interprocess Communicatoin),表示一组系统调用,这组系统调用
    			允许用户态进程:
    				a.通过信号量和其他进程进行同步
    				b.向其他进程发送消息或者从其他进程处接受消息
    				c.和其他进程共享一个线性区
    			使用IPC资源:
    				信号量:semget()
    				消息队列:msgget()
    				共享内存:shmget()
    				
    				
    		消息:允许进程异步地交换信息(小块数据)。可以认为消息是传递附加信息的信号。
    		共享内存:当进程之间在高效地共享大量数据时,这是一种最合适的交互方式。
    		套接字(socket):涉及到网络相关。
    		
    第十九章、程序的执行
    	1.进程概念:在Unix中是用来表示正在运行的一组程序竞争系统资源的行为。
    	2.内核需要处理的问题(把一组指令装入内存并让CPU执行):
    		不同的可执行文件格式:	Linux的一个著名之处就是能执行其他操作系统所编译的二进制文件。
    		共享库:	很多可执行文件并不包含运行程序所需要的所有代码,而是希望在运行时由内核从函数库装入函数。
    		执行上下文中的其他信息:	包括程序员熟悉的命令行参数与环境变量。
    		
    	3.进程的信任状和能力:Unix系统与每个进程的一些信任相关,信任状把进程与一个特定的用户或用户组捆绑在一起。
    	  信任状在多用户系统上尤为重要,因为信任状可以决定每个进程能做什么,不能做什么,这样既保证了每个用户个人数据的完整性
    	  也保证了系统整体上的稳定性。
    		a.进程的能力:一种能力仅仅是一个标志,它表明是否允许进程执行一个特定的操作或一组特定的操作。
    	4.库:所有的全局外部符号名的线性地址。这些地址的分配或解析是由连接程序完成的,链接程序把程序所有的目标文件收集起来并构造可执行文件。
    	5.静态库/共享库
    		动态库的优缺点:进程不需要拷贝目标代码、仅仅执行一个内存映射,把库文件的相关部分映射到进程的地址空间中。
    			缺点也很明显,动态的启动时间较长,移植性也不如静链接的好,系统中所包含的库版本发生变化时,
                           动态库连接的程序可能不适合本地运行。
    		静态库的优缺点:占用大量的磁盘空间。每个静态连接的可执行文件都复制库代码的一部分。 gcc编译器提供-static选项告诉链接程序使用静态库。
    	
    	6.程序段和进程的线性区:
    		逻辑上,Unix程序的线性地址空间传统上被划分为几个叫段(segment)的区间:
    			a.正文段:包含可执行代码。
    			b.数据段:包含初始化的数据,也就是说,初始值存放在可执行文件中的所有静态变量和全局变量(因为程序在启动时必须知道它们的值)
    			c.bss段:包含未初始化的数据,也就是说,初值没有存放在可执行文件中的所有全局变量(因为程序在引用它们之前才赋值)
    			d.堆栈段:包含程序的堆栈,堆栈中有返回地址、参数和被执行函数的局部变量。
    			
    		堆:线性区包含动态分配给进程的内存区。
    		/sbin/init程序,它创建和监视在操作系统外层实现的所有进程的活动。init进程对应的线性区可以从(/proc/1/maps)文件得到这样的信息。
    		
    	7.执行跟踪(execution tracing):是一个程序监视另一个程序执行的一种技术。被跟踪的程序一步一步地执行,直到接受到一个信号或调用一个系统调用。
    	   执行跟踪由调试程序(debugger)广泛应用,当然还使用其他技术(包括在被调试程序中插入断点及运行时访问它的变量)。
    	8.ptrace()系统调用进程执行跟踪。设置了CAP_SYS_PTRACE能力的进程可以跟踪系统中的任何进程(除了init)。
               相反,没有CAP_SYS_PTRACE能力的进程P只能跟踪
    	  与P有相同属主的进程。此外,两个进程不能同时跟踪一个进程。
    		a.ptrace()系统调用修改被跟踪进程描述符的p_pptr域以使它指向跟踪进程,因此,跟踪进程变为被跟踪进程的有效父进程
    		  跟踪结束时,以PTRAC_DETACH命令调用ptrace()时,这个系统调用把p_pptr设置为p_oppter的值,恢复被跟踪进程原来的父进程。
    		b.被跟踪进程相关的几个监控事件为:
    			一条单独汇编指令执行的结束
    			进入一个系统调用
    			从一个系统调用退出
    			接收到一个信号
    		c.当一个监控的事件发生时,被跟踪的程序停止,并将SIGCHID信号发送给它的父进程。当父进程希望恢复子进程的执行时,
                       就是用PTRACE_CONT、PTRACE_SINGLESTEP和
    		  PTRACE_SYSCALL命令中的一条,这取决于父进程要监控那种事件。
    		 
    	9.可执行格式:Linux正式的可执行格式是ELF(Execuable and Linking Format)。
    		类型为linux_binfmt的对象所描述的可执行格式实质上提供以下三种方法:
    			a.loadbinary:通读存放在可执行文件中的信息为当前进程建立一个新的执行环境。
    			b.load_shlib:用于动态地把一个共享库捆绑到一个已经在运行的进程,这个是由uselib()系统调用激活的。
    			c.core_dump:在名为core的文件中存放当前进程的执行上下文。这个文件通常是在进程接收到一个缺省操作为"dump"的信号时被创建的
    			  其格式取决于被执行程序的可执行类型。
    			  
    		linux_binfmt对象:处于一个简单的连接链表中,第一个元素的地址被存放在formats变量中。
                                                      可以通过调用register_binfmt()和unregister_binfmt()函数
    						 在链表中插入和删除元素。
    						 
    		formats链表中的最后一个元素:是一个对解释脚本(interpreted script)的可执行格式进行描述的一个对象。定义了load_binary()方法。
                    其相应的do_load_script()
                           可执行文件是否是以两个#!开始,如果是,这个函数就以另一个可执行文件的路径作为参数解释第一行的其余部分,
                           并把文件名作为参数传递过去以执行这个脚本文件。
    									
    		Linux允许用户注册自己定义的可执行格式:用如下的格式项/proc/sys/fs/binfmt_misc/register文件写入一个字符串
                               :name:type:offset:string:mask:interpreter:
                                   name:新格式的标识符
                                   type:识别类型(M表示魔数,E表示扩展)
                                   offse:魔数在文件中的起始偏移量
                                   string:或者以魔数,或者以扩展名匹配的字节序列
                                   mask:屏蔽string中的一些位的字符串
                                   interpreter:程序解释器的完整路径名
    											  
    		可执行文件的前128字节填充linux_binprm结构的buf域。
    		exec类函数:这些函数能用可执行文件所描述的新上下文代替进程的上下文。
    展开全文
  • Linux内核的整体架构简介

    万次阅读 多人点赞 2017-10-23 17:44:42
    本文是“Linux内核分析”系列文章的第一篇,会以内核的核心功能为出发点,描述Linux内核的整体架构,以及架构之下主要的软件子系统。之后,会介绍Linux内核源文件的目录结构,并和各个软件子系统对应。 注:本文和...

    1. 前言

    本文是“Linux内核分析”系列文章的第一篇,会以内核的核心功能为出发点,描述Linux内核的整体架构,以及架构之下主要的软件子系统。之后,会介绍Linux内核源文件的目录结构,并和各个软件子系统对应。

    注:本文和其它的“Linux内核分析”文章都基于如下约定:  
    a) 内核版本为Linux 3.10.29(该版本是一个long term的版本,会被Linux社区持续维护至少2年),可以从下面的链接获取:https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.10.29.tar.xz 
    b) 鉴于嵌入式系统大多使用ARM处理器,因此涉及到体系结构部分的内容,都以ARM为分析对象

    2. Linux内核的核心功能

    如下图所示,Linux内核只是Linux操作系统一部分。对下,它管理系统的所有硬件设备;对上,它通过系统调用,向Library Routine(例如C库)或者其它应用程序提供接口。

    image

    因此,其核心功能就是:管理硬件设备,供应用程序使用。而现代计算机(无论是PC还是嵌入式系统)的标准组成,就是CPU、Memory(内存和外存)、输入输出设备、网络设备和其它的外围设备。所以为了管理这些设备,Linux内核提出了如下的架构。

    3. Linux内核的整体架构

    3.1 整体架构和子系统划分

    image

    上图说明了Linux内核的整体架构。根据内核的核心功能,Linux内核提出了5个子系统,分别负责如下的功能:

    1. Process Scheduler,也称作进程管理、进程调度。负责管理CPU资源,以便让各个进程可以以尽量公平的方式访问CPU。

    2. Memory Manager,内存管理。负责管理Memory(内存)资源,以便让各个进程可以安全地共享机器的内存资源。另外,内存管理会提供虚拟内存的机制,该机制可以让进程使用多于系统可用Memory的内存,不用的内存会通过文件系统保存在外部非易失存储器中,需要使用的时候,再取回到内存中。

    3. VFS(Virtual File System),虚拟文件系统。Linux内核将不同功能的外部设备,例如Disk设备(硬盘、磁盘、NAND Flash、Nor Flash等)、输入输出设备、显示设备等等,抽象为可以通过统一的文件操作接口(open、close、read、write等)来访问。这就是Linux系统“一切皆是文件”的体现(其实Linux做的并不彻底,因为CPU、内存、网络等还不是文件,如果真的需要一切皆是文件,还得看贝尔实验室正在开发的"Plan 9”的)。

    4. Network,网络子系统。负责管理系统的网络设备,并实现多种多样的网络标准。

    5. IPC(Inter-Process Communication),进程间通信。IPC不管理任何的硬件,它主要负责Linux系统中进程之间的通信。

    3.2 进程调度(Process Scheduler)

    进程调度是Linux内核中最重要的子系统,它主要提供对CPU的访问控制。因为在计算机中,CPU资源是有限的,而众多的应用程序都要使用CPU资源,所以需要“进程调度子系统”对CPU进行调度管理。

    进程调度子系统包括4个子模块(见下图),它们的功能如下:

    scheduler

    1. Scheduling Policy,实现进程调度的策略,它决定哪个(或哪几个)进程将拥有CPU。

    2. Architecture-specific Schedulers,体系结构相关的部分,用于将对不同CPU的控制,抽象为统一的接口。这些控制主要在suspend和resume进程时使用,牵涉到CPU的寄存器访问、汇编指令操作等。

    3. Architecture-independent Scheduler,体系结构无关的部分。它会和“Scheduling Policy模块”沟通,决定接下来要执行哪个进程,然后通过“Architecture-specific Schedulers模块”resume指定的进程。

    4. System Call Interface,系统调用接口。进程调度子系统通过系统调用接口,将需要提供给用户空间的接口开放出去,同时屏蔽掉不需要用户空间程序关心的细节。

    3.3 内存管理(Memory Manager, MM)

    内存管理同样是Linux内核中最重要的子系统,它主要提供对内存资源的访问控制。Linux系统会在硬件物理内存和进程所使用的内存(称作虚拟内存)之间建立一种映射关系,这种映射是以进程为单位,因而不同的进程可以使用相同的虚拟内存,而这些相同的虚拟内存,可以映射到不同的物理内存上。

    内存管理子系统包括3个子模块(见下图),它们的功能如下:

    mman

    1. Architecture Specific Managers,体系结构相关部分。提供用于访问硬件Memory的虚拟接口。

    2. Architecture Independent Manager,体系结构无关部分。提供所有的内存管理机制,包括:以进程为单位的memory mapping;虚拟内存的Swapping。

    3. System Call Interface,系统调用接口。通过该接口,向用户空间程序应用程序提供内存的分配、释放,文件的map等功能。

    3.4 虚拟文件系统(Virtual Filesystem, VFS)

    传统意义上的文件系统,是一种存储和组织计算机数据的方法。它用易懂、人性化的方法(文件和目录结构),抽象计算机磁盘、硬盘等设备上冰冷的数据块,从而使对它们的查找和访问变得容易。因而文件系统的实质,就是“存储和组织数据的方法”,文件系统的表现形式,就是“从某个设备中读取数据和向某个设备写入数据”。

    随着计算机技术的进步,存储和组织数据的方法也是在不断进步的,从而导致有多种类型的文件系统,例如FAT、FAT32、NTFS、EXT2、EXT3等等。而为了兼容,操作系统或者内核,要以相同的表现形式,同时支持多种类型的文件系统,这就延伸出了虚拟文件系统(VFS)的概念。VFS的功能就是管理各种各样的文件系统,屏蔽它们的差异,以统一的方式,为用户程序提供访问文件的接口。

    我们可以从磁盘、硬盘、NAND Flash等设备中读取或写入数据,因而最初的文件系统都是构建在这些设备之上的。这个概念也可以推广到其它的硬件设备,例如内存、显示器(LCD)、键盘、串口等等。我们对硬件设备的访问控制,也可以归纳为读取或者写入数据,因而可以用统一的文件操作接口访问。Linux内核就是这样做的,除了传统的磁盘文件系统之外,它还抽象出了设备文件系统、内存文件系统等等。这些逻辑,都是由VFS子系统实现。

    VFS子系统包括6个子模块(见下图),它们的功能如下:

    vfs

    1. Device Drivers,设备驱动,用于控制所有的外部设备及控制器。由于存在大量不能相互兼容的硬件设备(特别是嵌入式产品),所以也有非常多的设备驱动。因此,Linux内核中将近一半的Source Code都是设备驱动,大多数的Linux底层工程师(特别是国内的企业)都是在编写或者维护设备驱动,而无暇估计其它内容(它们恰恰是Linux内核的精髓所在)。

    2. Device Independent Interface, 该模块定义了描述硬件设备的统一方式(统一设备模型),所有的设备驱动都遵守这个定义,可以降低开发的难度。同时可以用一致的形势向上提供接口。

    3. Logical Systems,每一种文件系统,都会对应一个Logical System(逻辑文件系统),它会实现具体的文件系统逻辑。

    4. System Independent Interface,该模块负责以统一的接口(快设备和字符设备)表示硬件设备和逻辑文件系统,这样上层软件就不再关心具体的硬件形态了。

    5. System Call Interface,系统调用接口,向用户空间提供访问文件系统和硬件设备的统一的接口。

    3.5 网络子系统(Net)

    网络子系统在Linux内核中主要负责管理各种网络设备,并实现各种网络协议栈,最终实现通过网络连接其它系统的功能。在Linux内核中,网络子系统几乎是自成体系,它包括5个子模块(见下图),它们的功能如下:

    net

    1. Network Device Drivers,网络设备的驱动,和VFS子系统中的设备驱动是一样的。

    2. Device Independent Interface,和VFS子系统中的是一样的。

    3. Network Protocols,实现各种网络传输协议,例如IP, TCP, UDP等等。

    4. Protocol Independent Interface,屏蔽不同的硬件设备和网络协议,以相同的格式提供接口(socket)。

    5. System Call interface,系统调用接口,向用户空间提供访问网络设备的统一的接口。

     

    至于IPC子系统,由于功能比较单纯,这里就不再描述了。

    4. Linux内核源代码的目录结构

    Linux内核源代码包括三个主要部分:

    1. 内核核心代码,包括第3章所描述的各个子系统和子模块,以及其它的支撑子系统,例如电源管理、Linux初始化等

    2. 其它非核心代码,例如库文件(因为Linux内核是一个自包含的内核,即内核不依赖其它的任何软件,自己就可以编译通过)、固件集合、KVM(虚拟机技术)等

    3. 编译脚本、配置文件、帮助文档、版权说明等辅助性文件

    下图示使用ls命令看到的内核源代码的顶层目录结构,具体描述如下。

    kernel_src_tree

    include/ ---- 内核头文件,需要提供给外部模块(例如用户空间代码)使用。

    kernel/ ---- Linux内核的核心代码,包含了3.2小节所描述的进程调度子系统,以及和进程调度相关的模块。

    mm/ ---- 内存管理子系统(3.3小节)。

    fs/ ---- VFS子系统(3.4小节)。

    net/ ---- 不包括网络设备驱动的网络子系统(3.5小节)。

    ipc/ ---- IPC(进程间通信)子系统。

    arch// ---- 体系结构相关的代码,例如arm, x86等等。 
        arch//mach- ---- 具体的machine/board相关的代码。 
        arch//include/asm ---- 体系结构相关的头文件。 
        arch//boot/dts ---- 设备树(Device Tree)文件。

    init/ ---- Linux系统启动初始化相关的代码。 
    block/ ---- 提供块设备的层次。 
    sound/ ---- 音频相关的驱动及子系统,可以看作“音频子系统”。 
    drivers/ ---- 设备驱动(在Linux kernel 3.10中,设备驱动占了49.4的代码量)。

    lib/ ---- 实现需要在内核中使用的库函数,例如CRC、FIFO、list、MD5等。 
    crypto/ ----- 加密、解密相关的库函数。 
    security/ ---- 提供安全特性(SELinux)。 
    virt/ ---- 提供虚拟机技术(KVM等)的支持。 
    usr/ ---- 用于生成initramfs的代码。 
    firmware/ ---- 保存用于驱动第三方设备的固件。

    samples/ ---- 一些示例代码。 
    tools/ ---- 一些常用工具,如性能剖析、自测试等。

    Kconfig, Kbuild, Makefile, scripts/ ---- 用于内核编译的配置文件、脚本等。

    COPYING ---- 版权声明。 
    MAINTAINERS ----维护者名单。 
    CREDITS ---- Linux主要的贡献者名单。 
    REPORTING-BUGS ---- Bug上报的指南。

    Documentation, README ---- 帮助、说明文档。

    5. 附录

    5.1 参考资料

    第3章各个子系统的架构图,拷贝自如下的网页: 
    http://oss.org.cn/ossdocs/linux/kernel/a1/index.html

     

    原创文章,转发请注明出处。蜗窝科技,www.wowotech.net


    展开全文
  • Linux内核修炼之道》 之 高效学习Linux内核

    万次阅读 热门讨论 2010-07-15 23:10:00
    这本《Linux内核修炼之道》在卓越、当当、china-pub上也已经开卖了,虽然是严肃文学,但为了保证流畅性,大部分文字我还都是斟词灼句,反复的念几遍才写上去的,尽量考虑到写上去的每段话能够让读者产生什么疑惑,...

    世界悲结束了,章鱼哥也退役了,连非诚勿扰中的拜金女也突然的少了很多。这本《Linux内核修炼之道》在卓越当当china-pub上也已经开卖了,虽然是严肃文学,但为了保证流畅性,大部分文字我还都是斟词灼句,反复的念几遍才写上去的,尽量考虑到写上去的每段话能够让读者产生什么疑惑,然后也都会紧接着尽量的去进行解释清楚,中间的很多概念也有反复纠结过怎么解释能够更容易的理解,力求即使对于初学者也可以有很少阻碍的一气读完。同时我也把书中一部分自己的感悟抽出来整理了精华版,share出来。当然水平有限,错漏之处有发现而修订时遗漏的,也有尚没有发现的。这本书如果对您有用,乃我之幸事,如果无用,就在此先诚惶诚恐的向大家拜个不是了。

    在6月份做过一次《高效学习Linux内核》的presentation,下面是前面的一部分内容及讲义,或许对大家有用吧。至于剩余的,因为和之前博客中的部分文章内容差不多,就不贴了。

    **********************************************************************

    既然有高效,相对的就有低效。学习本身就是一件很玄乎的事情,有些人整天潇潇洒洒没见怎么用心就能够获得很好的成绩,而有些人则相反,即使投悬梁锥刺骨也还是成绩平平收获平平。这里面很大一部分的原因就是学习的方法。

    但是学习方法这样的题目并不好讲,因为基于每个人不同的情况,并没有那样一个标准的方法存在,所以讲起来就很容易成为一场大忽悠。就像我们的任志强先生前阵子演讲卖房子 的方法时,就因为太像一场忽悠,从而被听众扔了鞋。

     

    接下来我就通过自己的一些感悟,抛砖引玉来介绍一下如何比较高效的去学习 linux 内核。这些话并不局限于某个部分的内容,很像一句句的口号,我们也可以将它们看作内核学习的大字报。

    首先是第一句话:把内核当朋友。今年笑来老师有本新书,叫把时间当朋友,告诉我们只有把时间当朋友,才能更好的利用自己的时间做些有益的事情。同样,我们只有把内核当朋友,把它放在对等的地位上,而不仅仅是一堆死气沉沉的代码,我们才能够更好的认识和理解到它的精髓。

    然后是第二句话:先会使用它。意思就是我们在学习内核前首先要会用 linux ,依照一个由上至下循序渐进的过程,在能够熟练的使用 Linux 操作系统之后再去研究内核中的实现。这也是 linus 本人的观点。

    第三句是依照四个层次进行内核学习。笛卡儿在 17 世纪的某一天,闲极无聊写了这么一本书,书名就叫《方法论》,在这本目前来说绝大部分人都不知道的书里将方法上升到了理论的高度。笛卡儿在他的这本书里将研究问题的方法归纳为简单的一句话,就是 “ 复杂问题要简单化 ” 。就是说要将复杂的问题分解为很多个简单的小问题,一个个的分开解决。这句话当然可以借鉴运用到内核的学习上,不过需要做些改动,不是分解为多个简单的小问题,而是将内核学习这么一件很复杂的事情划分为由低到高多个不同的层次,每一层次都有自己需要达到的目标和要求。这也是我自己认为比较好的认识学习内核的方法。

    第四句是走出心理误区。 对于学习这种复杂的事情来说,无论是我们在学校的课堂学习,还是这里说的内核学习,它的效果好与坏,最主要取决于两个方面:一个是学习的方法,另一个就是学习时的心理。注意,在这儿我无视了智商的差异,智商这玩意儿太玄了,可以将它归于迷信的范畴。而我们在学习时经常会产生一系列的问题或者说误区,只有走出这些误区,在学习中养成一个坚强的心理,我们才能够真正的做到高效。

    第五句是使用 vim+cscope+ctags 浏览内核源码。其实这句话更主要的意思是说我们需要一个好的工具去浏览内核的代码。在 windows 下面,我们或许可以很容易的找到很多比较好的 IDE 可以用来浏览代码,比如 source insight ,它可以很方便的在代码之间进行关联阅读。但是对于 Linux 新人来说,有没有一个功能类似的浏览代码的工具就成为一个很常见的问题。

    第六句是使用 kernel 地图定位目标代码。应该说学习内核就是学习内核的源代码,但是内核代码千千万,又到处像个迷宫一样,不迷路都很难,又怎么去直面它?这时我们就需要这样的一幅内核地图来帮助我们去定位所要分析的目标代码,并缩小目标代码的范围与代码量。

    接下来是第七句话:分析内核源码,态度决定一切。我们很多人或许有这样的困惑,也分析浏览了很多内核的源码,可总是觉得分析完浏览完脑子里还是空空的,并没有感觉到多大的收获。这个时候我们或许可以去看看是不是自己在分析代码时的态度出现了问题。我们在分析内核源码时,只有遵循严谨的态度,去理解每一段代码的实现,多问多想多记,而不是抱着走马观花,得过且过的态度,最终必然会有很大的收获。

    最后一句是:以内核源码为中心,坚持学习资源建设。在我们内核学习的过程中,内核源码本身就是最好的参考资料,其他任何经典或非经典的书最多只是起到个辅助作用,不能也不应该取代内核代码在我们学习过程中的主导地位。但是这些辅助的作用也是不可忽视的,我们需要以内核源码为中心,坚持各种学习资源的长期建设不动摇。

    除了这里的八句话,其他的可能会对大家有帮助的感悟或者方法还有很多 。

     

    把内核当朋友,就是要把内核看成一个鲜活的生命体,而不是一堆死气沉沉的代码。

    具体一点来说,我们在学习与浏览内核的实现时,可以将它看成是现实世界的映射。内核是由现实中的人写出来的,因此不管是有意还是无意,都会不可避免的包含了一些自己的现实感情,我们研究内核时可以体会下这种脉络,这种隐藏在代码背后的哲学。比如,我们可以认为内核是个大世界,一个个进程就是这个世界中的一个个生命体,进程管理和调度就是这个大世界中的权力机关,内存是进程的家,内核的目标就是要做到使每个进程都居者有其屋。

    既然要把内核看成是一个鲜活的个体,那么我们认识它的第一件事就是了解它的一些基本信息,就像我们人与人之间互相认识首先也是通过个人的基本信息一样。

    首先从名字开始, kernel 在字典中主要有两种定义,一种是 “ 软的,一个坚果可食用的部分 ” ,对 Linux kernel 来说,当然适用的是第二种定义: “ 某个东西的核心部分 ” 。所以从广义上来说, linux kernel 就是 linux 操作系统里最为核心的部分,而从狭义上来说,它不过就是 Linus 那群人人写的那点儿代码。

    当然,这点儿代码是相当复杂的,单单从代码量上来说,早已经突破了千万级。从结构上来说,也早就不是一个人穷自己一己之力就能够全部理解的了。所以,现在强调第二句话:学内核切忌求大求全,选择一点研究的足够深入就很不容易了。

    下面介绍介绍 kernel 的年龄, kernel 又不是一个怀春的少女,所以它的年龄并不需要保密,从 1991 年诞生开始,在去年刚刚举行了它自己的成人礼,进入了成熟发展期。

    就像我们人有自己的青春期、中年期等一样, kernel 相应的也有很多不同的版本号,不过不同的是,我们的青春期一去就不复返了, kernel 不同的版本号却是共存的。

    很多年以来,内核的版本都是以 X.Y.Z 这 3 个数字的形式分配的,中间的偶数 Y 代表稳定版,奇数 Y 代表了不稳定的开发版。所谓的稳定版本是指内核的特性都已经固定,代码运行稳定可靠,不会再增加新的特性,要改进也只是修改代码中的错误。而不稳定版本是指相对于上一个稳定版本增加了新的特性,还处于发展之中,代码的运行不大可靠。

    对于目前来说, 2.6 内核的发布已经持续了很长时间,那么什么时候将会推出 2.7 ? Linus 本人的回答是,不会有 2.7 ,他不会再遵循旧的模式,新采用的模式会更好,不值得重复过去。他表示正在考虑新的编号方式,一种基于时间的版本号。比如用 2008.7 取代 2.6.26 ,中间第二个数字代表年, 2008 年就是 2.8 , 2009 年的第一个版本就是 2.9.1 ,之后 2010 年是 3.0 ,等等。

    最后不得不提到是那些眼花缭乱的发行版,内核与发行版的关系就类似那种双生花,彼此互相依赖互相扶持共同成长。没有那些发行版,内核就只能是束之高阁的一个貌似好看的玩具,并不能真正的走进我们的工作生活,而没有内核,那些发行版就缺少了存在的地基,就只能是个豆腐渣工程。

     

    现在我们了解了内核这个朋友的外表,这个时候我们不能像非诚勿扰中的那些拜金女一样只关心外在的信息,我们还要接着了解内核的内涵,也就是内核的体系结构以及内核是如何工作的。

    首先看第一张图,它向我们传递了这样的信息 —— 内核将应用程序和硬件分离开来。内核一方面负责与计算机硬件进行交互,实现对硬件的控制,调度对硬件资源的访问,另一方面为用户应用程序提供一个高级的执行环境和访问硬件的虚拟接口。

    提供硬件的兼容性是内核的设计目标之一,几乎所有的硬件,只要不是为其他操作系统所定制的,都可以得到 Linux 的支持。

    与硬件兼容性相关的是可移植性,也就是在不同的硬件平台上运行 Linux 的能力。从最初只支持标准 IBM 兼容机上的 Intel X86 架构到现在可以支持 ARM 、 MIPS 、 PowerPC 等几乎所有硬件平台,如此广泛的平台支持之所以能够成功,部分原因在于,内核清晰地划分为了体系相关部分和体系无关部分。因此也就有了第二张图。

    体系无关部分通常会定义与体系相关部分的接口,这样,内核向新的体系结构移植的过程就变成确认这些接口的特性并将它们加以实现的过程。

    同时,用户应用程序和内核之间的联系,一般是通过它和内核的中间层 —— 标准 C 库来实现,而标准 C 库函数本身,则是建立在内核提供的系统调用基础之上。通过标准 C 库,以及内核体系无关部分与体系相关部分的接口,用户应用程序和部分内核都成为可移植的。

    因此更为准确的是第三张图。其中,进程管理部分实现了一个进程世界的抽象,这个进程世界类似于我们的人类世界,只不过我们的世界里的个体是人,而在进程世界里则是一个一个的进程,我们人与人之间通过书信、手机、网络等交通往来,而各个进程之间则是通过不同方式的进程间通信,我们所有人都在分享同一个地球,而所有进程都在分享一个或多个 CPU 。

    在这个进程的世界里,内存是重要的资源之一,就好似我们的土地。因此,管理内存的策略与方式,也就是内存管理是决定系统性能的一个关键因素。

     

    了解了内核的体系结构,我们再来看看内核是如何工作的。

    首先,内核通过系统调用来使得运行在它上面的应用程序可用。系统调用是内核和应用程序之间的桥梁,比如图中的针对文件操作的 open() , close() , read() , write() ,针对进程操作的 fork() , wait() ,还有针对网络操作的 socket() 等等,它们提供了对硬件的抽象,所以有时也被称为 linux 虚拟机。

    内核提供的最接近实际用户的明显抽象是文件系统,我们很容易能够利用 open() 等几个系统调用编写一段程序打开一个文件并将它的内容拷贝到标准输出。内核通过这些系统调用为用户提供了一个文件的 " 错觉 " ,而实际上它不过是一堆数据有了个名字,这样一来就不必去与硬件底层的堆栈、分区和指针等交涉,这也就是我们经常所说的抽象 (abstraction) ,将底层的东西以更易懂的方式表达出来。

    文件系统是内核提供的比较明显的一种抽象,我们可以说它是位于台前的,而相对还有一些是位于幕后的,比如进程调度。在 linux 上,任何 一个时间,都可能有好几个进程或者程序等待着运行。内核的时间调度给每个进程分配 CPU 时间,所以就一段时间内来说,我们会有种错觉:电脑同一时间运行好几个程序。

    再比如另外一个位于幕后的内存管理,幕后到应用开发者都不易察觉的地步。每个程序运行得都好像它有个自己的地址空间来调用一样,实际上它跟其他进程一样共享计算机的物理存储。内存管理的另外一个方面是防止一个进程访问其他进程的地址空间 —— 对于多进程操作系统来说这是很必要的一个防范措施。

    当然位于台前幕后的还有其他的角色,比如网络等。

    我们现在再来简单看下它的物理组成。早期版本的内核是整体式的,也就是说所有的部分都静态地连接成一个很大的执行文件。

    喜欢的话,欢迎扫码关注:)

    展开全文
  • 非常好的Linux编译内核详解 - -

    万次阅读 2018-03-21 15:58:36
    转载: http://blog.chinaunix.net/uid-263488-id-2138150.html非常好的Linux编译内核详解 - -一、内核... Linux的一个重要的特点就是其源代码的公开性,所有的内核源程序都可以在/usr/src/linux下找到,大部分...
  • Linux用户空间与内核空间

    千次阅读 2016-04-25 10:07:27
    A.INTRODUCTION (32位系统) ... Linux 简化了分段机制,使得虚拟地址(逻辑地址)与线性... Linux内核将这4G字节的空间分为两部分。将最高的 1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称
  • linux内核完全剖析(0.11版本内核)V1.9.5,赵老师2004经典版
  • linux内核问题

    2019-11-30 22:03:56
    1) Linux中主要有哪几种内核锁? 2) Linux中的用户模式和内核模式是什么含意? 3) 怎样申请大块内核内存? 4) 用户进程间通信主要哪几种方式? 5) 通过伙伴系统申请内核内存的函数有哪些? 6) 通过slab分配器...
  • 3---Linux内核及内核编程

    千次阅读 2018-12-11 13:34:36
    什么是操作系统? 指在系统中负责完成最基本功能和系统管理的部分, 操作系统有哪些组成部分?...Linux内核源代码目录结构是什么,各目录有什么含义? arch:包含和硬件体系结构相关的代码,每种平台占一...
  • Linux内核组成部分(一)

    千次阅读 2019-01-11 10:31:38
    内核的任务 在纯技术层面上,内核是硬件与软件之间的一个中间层。其作用是将应用程序的请求传递给硬件,并充当底层驱动程序,对系统中的各种设备和组件进行寻址 从应用程序的视角来看,内核可以被认为是一台增强的...
  • Linux升级内核的正确姿势

    万次阅读 多人点赞 2018-08-20 23:41:18
    Linux升级内核的正确姿势 很多童鞋在玩耍linux发行版的时候,都会遇到各种各样的问题,比如:网卡不能使用,亮度不能调节,触摸板不能识别...Linux内核最早是于1991年由芬兰黑客林纳斯·托瓦兹为自己的个人计算机开...
  • 鉴于此,《Linux内核精髓:精通Linux内核必会的75个绝技》选取了资源管理(CPU、内存、进程等)、文件系统、网络、虚拟化、省电、调试、概要分析、追踪、内核调整等Linux内核的核心主题进行了深入剖析和讲解,总结出...
  • Linux内核学习四库全书

    万次阅读 热门讨论 2011-07-05 14:12:34
    关于内核学习我建议不要上来就读内核而是先了解内核的构成和特性,然后通过思考发现疑问这时再去读内核源码。即先了解概貌在读局部细节。... Linux内核设计与实现 Edition 2 2. Linux设备驱动 Edition 3 3. Linux
  • linux2.6.1内核源码注释

    万次下载 热门讨论 2014-03-10 15:21:33
    包含LINUX内核同步、信号、内存、调度、文件系统、网络系统、时钟等部分的源码注释。前后历时三年,算是干货。
  • linux内核编译详解

    万次阅读 2018-04-28 04:36:26
    前言Linux内核是Linux操作系统的核心,也是整个Linux功能体现的核心,就如同发动机在汽车中的重要性。内核主要功能包括进程管理、内存管理、文件管理、设备管理、网络管理等。Linux内核是单内核设计,但却采用了微...
  • Linux内核分析及编程高清pdf版(2-1)

    千次下载 热门讨论 2010-04-19 09:20:37
    本书作者在整理自己多年研发笔记的基础上,以精心挑选的典型开发实例,向读者详细讲述了Linux内核源代码的各部分结构、原理及组成框架,主要分析了 Linux最新版本(2.6.11)的内核源代码,帮助读者深入理解Linux内核...
  • Linux内核从原理到代码详解 链接: http://pan.baidu.com/s/1sj0Szj3 密码: ywyv 网盘失效的话,请加QQ: 3113533060 课程内容: 第一周 1. 初识Linux内核 1.1 认识操作系统 1.2 开放源代码的UNIX...
  • 学习linux内核是需要一步一步循序渐进,掌握正确的linux内核学习路线对学习至关重要,本篇文章就来分享学习linux内核的一些建议吧。 1. 了解操作系统基本概念。如果不会,可以学习《操作系统:设计与实现》Andrew S...
  • LINUX内核目录文件说明

    万次阅读 2018-08-03 09:40:31
    内核空间和用户空间  在下载内核前,我们应该讨论一些重要的术语和事实。首先了解一下内核空间和用户空间 ... Linux内核是一个宏内核,这意味着整个操作系统都运行在内核预留的内存里。 内...
  • Linux内核精髓:精通Linux内核必会的75个绝技》前言 内核是操作系统的核心,操作系统的基本功能都是由内核提供的。文件生成和数据包传输等也是通过内核的功能实现的。但这些都不是简单的任务。平时可能意识不到...
  • Linux内核定时器

    千次阅读 2019-05-23 20:21:48
    时间系统的工作需要软硬件以及操作系统的互相协作,在上一部分,我们已经看到大多数时间函数都依赖内核系统调用,GlibC 仅仅做了一次请求的转发。因此必须深入内核代码以便了解更多的细节。 内核自身的正常运行也...
  • 之前在读《APUE》的时候,更多的是从上层去了解如何使用Linux系统的API,那个时候就十分喜欢Linux的...在linux内核方面,目前打算阅读两本书,《Linux内核设计与实现》就是其中一本,另一本是《深入理解linux内核》。
  • 如何参与linux内核开发

    千次阅读 2016-05-02 22:43:05
    如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 译存在问题,请联系中文版维护者。...中文版维护者: 李阳 Li Ya
  • 我的Linux内核学习之路

    万次阅读 多人点赞 2014-03-02 18:34:28
    现在回首看看,接触Linux已经很长时间了。 在大三的时候开始学习Java, 但是一直学Java的话, 感觉有点腻, 就尝试找点其他东西来学习。 所以当时就选择学习了Linux。 至于为什么要学习Linux, 有以下三个原因。  ...
  • Linux 内核分析及应用

    千次阅读 2018-11-06 11:55:57
    本书分模块介绍了 Linux 操作系统的内核设计和实现,针对关键概念、算法和数据结构做了重点的讲解。同时,对诸多经典应用程序进行了剖析,如 Nginx、Memcached、Redis、LVS 等,讲解如何利用操作系统提供的底层支持...
  • 操作系统内核可能是微内核,也可能是单内核(后者有时称之为宏内核Macrokernel)。按照类似封装的形式,这些术语定义如下: 单内核:也称为宏内核。将内核从整体上作为一个大过程实现,并同时运行在一个...
  • linux内核   linux内核版本号格式   major.minor.patch-build.desc  1、major:表示主版本号,有结构性变化时才变更。  2、minor:表示次版本号,新增功能时才发生变化;一般奇数表示测试版,偶数表示...
  • Linux内核学习书籍

    万次阅读 2018-10-11 15:43:29
    关于内核学习我建议不要上来就读内核而是先了解内核的构成和特性,然后通过思考发现疑问这时再去读内核源码。即先了解概貌在读局部细节。而且内核分成好多部分,不要只是按照顺序去读,应该...Linux Kernel 四库全...
  • 3.3 Linux内核的组成3.3.1 Linux内核源代码的目录结构Linux内核源代码包含如下目录。arch:包含和硬件体系结构相关的代码,每种平台占一个相应的目录,如i386、arm、arm64、powerpc、mips等。Linux内核目前已经...
  • Linux内核编译

    万次阅读 2018-09-03 15:38:41
    下面简单介绍一下Linux内核编译过程。(附注:本博客所讲的内容是在Ubuntu上进行操作的,Cent OS并未验证) 1、下载内核源码,可以到kernel.org上进行下载。 2、解压内核源文件(注意:要先使用cd命令进入压缩包...

空空如也

1 2 3 4 5 ... 20
收藏数 699,369
精华内容 279,747
关键字:

linux内核

linux 订阅