Chinaunix首页 | 论坛 | 博客
  • 博客访问: 58139
  • 博文数量: 13
  • 博客积分: 1420
  • 博客等级: 上尉
  • 技术积分: 120
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-08 16:58
文章分类

全部博文(13)

文章存档

2011年(1)

2009年(12)

我的朋友

分类: LINUX

2009-07-23 16:34:10

结束动作。ldconfig –r workdir/rootfs(试验文件系统目录) 建立库文件路径缓存 ,从此命令再使用动态连接库时就不必指定目录了,因为它们的路径都被缓存了。(ldconfig 要用动态库配置文件ld.so.conf,试验系统中置空它好了)

安装根文件系统——内核和root文件系统绑定
别混淆,刚刚我们做的是文件系统应该包含的文件。具体文件系统现在才开始做。上面说了需要在系统未来的宿主盘上制作文件系统——进行格式化。如果你手头没有实际设备,Linux提供给你另外两种变通方法 : ramdiskloop设备(回环设备) 。利用loop设备可以将文件虚拟成一个文件系统进行安装,而ramdisk则是将内存模拟一个块设备用来存放数据。

    使用ramdiskloop设备相比直接使用物理磁盘操作要快一些,也相对安全,不会损坏物理设备。因此在需要创建文件系统的情况下,很多时候都会使用上面两种虚拟技术创建文件系统,然后在将文件系统转移到物理设备中。

    我们采取ramdisk作为文件系统的宿主,在上面制作文件系统,然后拷贝我们前面创建的文件系统内容到其上去。然后观察ramdisk的大小后 (可不是其中文件内容的大小,因为其中还包含文件系统本身格式的一些信息),将整个文件系统统转移到某个文件中去(利用dd命令,由于 dd 命令允许二进制方式读写,所以特别适合在原始物理设备上进行输入/输出,制作整个文件系统的镜像),该文件被称为文件系统镜像。虽然Linux对文件后缀没有要求,但这里我们还是习惯以img命名它。

    具体做法大该如此:

         dd if=/dev/zero of=/dev/ram bs=1k count=20000

          mke2fs –m0 /dev/ram 20000

          mount /dev/ram /mnt/

          cp –av /rootfs/*  /mnt/ram

          运行df ,注意1k-blocks一栏中/dev/ram的数值,假定为ramsize

          umount /dev/ram

          dd if=/dev/ram of=ramlinux.img bs=1k count=ramsize 

        gzip –9v ramlinux.img

  第一步是给 /dev/ram设备清出20M的全零空间,然后格式化/dev/ram设备,页就是将格式信心写入/dev/ram中。

 接下来,安装/dev/ram设备到/mnt目录下,再把你创建的文件系统内容全部考进来。完成了这步,你才可以说真正有了一个文件系统(文件系统格式信息+文件系统内容)

 然后解载设备后,把设备内容(包含文件系统格式和内容)统统转移到名为ramlinux.img的镜像文件中,

最后压缩镜像文件(压缩后名字为ramlinux.img.gz),开始使用/dev/zero清零/ram设备地目的就是为了提高压缩率,因为压缩算法利用统计规律替换字符,所以统一为零会大大提高gzip的压缩率的。

一般标准系统中ramdisk默认大小为4098字节,你不能建立超过该大小的ram盘。但我们搭建的系统大小超过了4096字节,所以必须扩大ramdisk的大小。最简单的方法是在lilo启动时给ramdisk指定大小,实现系统中大概用到20M大空间,所以在Lilo.conf中应该加入“append = “ramdisk_size=20000”这一行,系统启动时就会自动更改ramdisk默认大小了。

 

系统引导引导过程简述PC打开电源后,先执行ROMBIOS中的代码,该程序负责将启动设备(软盘、硬盘、光盘)的第一个扇区(0扇区)第一个磁到道的数据载入内存。接着BIOS执行该扇区中的代码(将内核从启动设备中逐步导入到内存)。所以扇区中要么直接存放操作系统内核,要么存放启动装载程序,比如Lilo等,由启动装载程序负责找到内核,装载内核到系统,然后执行内核。

   内核被载入内存后的动作上面已经初步介绍了,我们这里要强调的是内核初始化以后紧接着就需要安装根文件系统,那么根文件系统的位置如何确定?(ramdisk size?

       我们必须在创建过程中指定驱动设备,利用命令

rdev filename devicename 设置或在内核原代码目录下的 makefile中修改相关参数,然后编译,因为该信息是备记录在内核中的。

除了跟文件设备外还需要指出根文件系统在宿主设备上的位置,这还需要利用rdev 来实现。该信息也被记录在内核中。(rdev命令很丰富,回忆我们前面谈到的改变ram盘大小的任务都可以通过rdev来修改)

可能很多朋友奇怪自己根本没用过这个命令,这么多年还不照样把系统生级了无数次。的确我们不大使用该命令,因为我们有更酷的工具lilo(当然grub好像现在更流行了),lilo.conf中的配置如root=* 这些选项其实就是告诉lilo将上述信息写道内核中。

确定了根文件系统位置,将其安装到根目录下,然后找到其中init程序,开始执行系统初始化工作。

 

安装启动镜像
大家多数都应该对 lilo.conf下的intrd=initrd.img.*有印象吧。你知道initrd.img是干嘛用的吗?

这个文件实际上就是个文件系统镜像,有兴趣的话你可以将它登陆到/mnt下,去看看,它毫无疑问是个微缩的文件系统(该文件使用gzip压缩的,所以先要解压才能安装它。(

mv initrd.img initrd.img.gz;gunzip initrd.img.gz;mount –o loop initrd.img /mnt)。这个文件里的各目录和我们文件系统是完全一样的,但是由于initrd.img是在系统启动后在Ram盘里运行的所以它只包含系统启动时需要的最小命令和库的集合。使用这个萎缩文件系统的目的通常是为了系统启动是尚未安装根文件系统前,用来运行系统以便利用insmod命令装入安装根文件系统需要的模块——比如ext3.o,Buslogic.o等(如果根设备是SCSI或根文件系统是EXT3等,而内核并为将这些功能编译进去,只能以模块方式载入),所以在initrd.img中的lib下会包含需要再入的模块。系统启动后运行intrd.img中的linuxrc脚本来执行模块载入后将根文件系统切换到实际文件系统中(使用pivot_root命令)。

对于我们实验系统来说,因为已经将SCSIEXT3等模块直接编译进了内核,所以不必通过initrd.img的途径来进行先期模块载入。因此正常情况下initrd.img是不需要的。但是要知道我们制作的根文件系统镜像是放在源标准系统根文件系统下的。所以要使得系统拍托实际物理设备,进入ram盘工作运行,就需要利用intrd.img镜像文件系统在启动期间将物理盘上根文件系统镜像载入ram盘中,然后进入执行。这个工作我们利用linuxrc脚本来实现,具体地讲就是mount源根文件系统,将试验文件系统镜像解压传送到/dev/ram中,然后umount 源根文件系统。从此系统进入我们的实验文件系统开始运行。

Initrd.img也是属于文件系统镜像,它的制作方法和制作根文件系统大通小异。先拷贝需要文件,在编辑脚本(linuxrc),然后制作文件系统镜像。详细过程不再罗索了。

 

别着急,还有关键一步那就是修改lilo .conf 为实验系统配置启动选项。

boot =实验系统内核

label = ramlinux

initrd = 刚做的initrd镜像

root = /dev/ram

append = “Ramdisk_size = 20000”

最后,执行lilo –r /rootfs

ok

有关内核引导请见附件。

 

下载搭建脚本和实验系统系统
虽然搭建系统技术简单,但是过程很繁琐,搞不好会丢三拉四,错误百出。为了节约大家的体力,我们编写了几个小脚本帮助搭建系统。利用这几个脚本大家可以轻松地自动建立实验系统。

我们的制作脚本可分为下面几个部分:

mkrootfs.sh—— 收集制作root文件系统所需的所有材料到指定目录。

mkinitrdfs.sh——收集制作initrd镜像所需的所有材料到指定目录。

setup.sh——制作root文件系统镜像和initrd镜像,改写lilo配置文件添加ramlinux启动选项。

连同脚本一同提供给你的还有mybootmyetc myroot目录。boot里含有编译好的内核(注意内核是与系统硬件相关的,我的机器是奔三处理器,如果你系统和我不同,那你还是自己在本机上编译试验系统内核吧!不过可以使用我们提供的内核配置文件MinSys.config来选择内核功能,编译完成把内核考贝到myboot下就可以了——或修改mkimage.sh脚本,在最后面的地方修改lilo.conf部分,将”boot=×××”中的XXX用你自己编译的内核代替)、模块和内核配置文件MiniSys.configetc下包含了供试验系统使用的、已经修改好的配置文件和服务脚本。Boot下是两个bash的配置文件--全部脚本和必要配置文件打包为work.tar.gz

此外,我们也将按上述方法裁减出来的root文件系统(rootfs.tar.gz)root文件系统镜像ramlinux.img.gz放在网上以供下载,同时也把initrd的内容(initrdfs.tar.gz)和镜像(initrd.img.gz)放在网上。

如果你要添加或删除文件系统中的某些文件,应该展开roofs.tar.gz,然后在rootfs里面修改,不要把文件系统镜像文件(img文件)loop方式安装后进行修改,因为我们曾经用zero设备填充过文件系统,所以如果新添加或删除某些内容,可能会破坏里面的一些数据对齐,系统反映给你的就可能会有类似于“bus error”等一类莫名奇妙的错误。

如果你按要求解开了rootfs.tar.gzinitrdfs.tar.gz,那么执行setup.sh既可生成对应的镜像文件ramlinux.img.gzinitrd.img.gz,并会在lilo中添加好对应于试验系统的选项。

Step by step——享受你的操作系统吧
从启动菜单中选择ramlinux开始运行吧!

等等,要输入管理员密码?是的,我们是从原有的系统中裁减的,所以密码自然会继承下来。(如果你用的是我做好的系统,那么用户名自然是root,密码 threeyear

      看见了吗,亲手打造的操作系统已经快步向你走来,有成就感吗?享受你的杰作吧!

 

 

附件——Linux系统启动的标准流程
系统的启动是指从计算机加电到显示用户登陆提示的整个过程。我们将在这里对整个流程以及关系到的一些内容做讨论。过程主要可以分为两个阶段:载入内核和准备运行环境,我们分别进行讨论。本部分的讨论只基于i386 件架构,但大部分内容是有共通性的。

http://blog.csdn.net/images/blog_csdn_net/jdmba/110399/r_photo5.jpg


图一 启动过程 综述

载入内核(将内核载入内存,并将控制权传递给它)
      
计算机加电到Boot Loader开始工作,硬件含量远大于软件含量,所以这里暂不提及,如果实在有关心的朋友,请先别着急,我们将在下期里讨论它。

这一阶段是 Boot Loader 的主战场。它必须将可执行的内核映像和内核启动所需的额外数据信息从存储介质上载入内存,这并不是件简单的工作,因为除了从硬盘载入,可能还会需要从网络引导服务器这样的外部介质上载入。各种纷繁芜杂的文件系统类型也给载入带来了巨大的挑战。

Boot Loader 可能还需要改变CPU的运行特权级别,然后就可以让内核投入运行了。

除此之外, Boot Loader 还要完成一些其它功能,比如从BIOS中获取系统信息,或者从启动时的命令行参数中提取信息等。有的 Boot Loader 还要扮演引导选择工具的角色,方便用户选择不同的操作系统。

Boot Loader 职责:
判断到底要载 入什么,这可以要求用户进行选择

载入内核和它 可能需要用到的相关数据,比如initrd或者其它参数

为内核准备好 运行环境,比如,让CPU进入特权模式

让内核投入运

Boot Loader 历史变迁:
早期的Linux只支持软盘引导扇区和 Shoelace 两种 Boot Loader Shoelace 是从Minix继承下来的、对文件系统相关的 Boot Loader。它只支持 Minix 文件系统。当时Linux只使用 Minix 一种文件系统,所以这样做并没什么问题。可是, Minix 文件系统存在不能保存创建、修改和访问时间信息;文件名长度限制在14个字节等问题。随着Linux的发展,这些与传统Unix文件系统大相径庭的缺陷越来越让人难以忍受,它已经不适合作为Linux的主要文件系统了。

为了支持其它文件系统的实现,Linux引入了VFS(虚拟文件系统)。这个举措很快就引起了热烈的反响,一大批新的文件系统实现出现了。其中一个 Minix 文件系统的变体,扩展文件系统 Xiafs (根据它的作者命名)突破了 Minix 文件系统的文件名长度限制,将此长度一举提高到全部30个字符。当时文件系统之间的竞争着实激烈,很难看出谁会胜出,甚至搞不清楚会不会有一个最终的赢家

       尽管不确定性很大,但是有一点却是清楚的:不管最后哪种文件系统会受到青睐,但是除了 Minix 作为根文件系统,谁也不能从硬盘上启动,因为 Shoelace 只支持Minix文件系统。LILO应运而生了。由于支持多种文件系统(当时内核支持的主流文件系统已经有 Minix ,扩展文件系统 ext Xiafs 。还有人在移植 BSD FFS ,根本看不出来什么时候是个尽头)在实现和维护上难度太大,而 Boot Loader 也不应该成为人们试验新的文件系统的绊脚石,所以LILO采取了和文件系统无关的设计。

这种设计经受住了时间的考验,被证明是非常成功的。即使在今天,LILO仍旧可以从内核支持的绝大部分文件系统的硬盘上启动。但是,由于ext2历经这么长的时间一直没有大的演变,成为了事实上的标准,所以跟文件系统相关的Boot Loader又渐渐流行了起来。

尽管ext2已经能满足大部分人的日常需要,但是文件系统的设计者们还是在研制以日志机制为特征的新的文件系统,并且已经取得了相当大的进展。考虑到当前又有可能出现多种文件系统的实现同时并存的情况,因此对与文件系统无关的Boot Loader的需求可能会再次变得强劲。

初始化基本的操作环境

一旦内核开始运行,它会初始化内部的数据结构,检测硬件,并且激活相应的驱动程序,为应用软件的准备运行环境。其间包含一个重要操作——应用软件的运行环境必须要有一个文件系统,所以内核必须首先装载root文件系统。由于我们的目的是介绍基本流程,所以相关的硬件初始化细节就不再讨论,相关内容在下一期杂志中会有详细介绍。

 

硬件初始化完成后,内核着手创建第一个进程——初始进程。说是创建,其实也不尽然,该进程其实是整个硬件上电初始化过程的延续,只不过执行到这里,进程的逻辑已经完备,所以我们就按照进程的创建方式给它进行了规格化” ——我们把这个初始进程也叫做硬件进程,它会占据进程描述符表的第一个位置,所以可以用task[0] INIT_TASK表示。该进程进而会再创建一个新进程去执行init()函数,其实,这个新进程才是系统第一个实际有用的进程,它会负责接着执行下一个阶段的初始化操作;而初始进程(INIT_TASK)自己则会开始执行idle循环,也就是说,内核初始化完成之后,初始进程唯一的任务就是在没有任何其它进程需要执行的时候,消耗空闲的CPU 间(因此初始进程也被称为idle进程)。

下一阶段的初始化工作要比前一阶段轻松一点,因为现在是由一个真正进程接手负责完成它们了,而前一阶段都是由硬件进程手工去做的。在此阶段,这个由INIT_TASK创建的新进程需要初始化总线、网络并启动系统中的各种系统内核后台线程,然后再初始化外设、设置文件格式,在这之后,它要为进入系统做最后的准备——初始化文件系统,安装root文件系统,打开/dev/console设备,重定向stdinstdoutstderr到控制台,然后搜索文件系统中的init程序,并使用 execve()系统调用加载执行init 序。系统自此进入了用户态。

 

装载root文件系统
为了装载文件系统,内核需要:1知道root文件系统位于那个存储介质上;2有访问该种介质的驱动程序。最常见的情况是rootext2文件系统,位于IDE硬盘上。这种情况下需要的操作很简单:将设备号作为参数给内核就可以了,IDE的设备驱动程序通常都会编译进内核的。

如果内核没有相关介质的驱动程序,问题就会变得更为复杂。而这种情况并不罕见,比如Linux的安装盘使用的通用内核一般都会碰到。如果内核把所有支持的硬件的设备驱动程序都包含进来,就会变成一个庞然大物;而且一些驱动程序在检测硬件的时候会影响其它设备。

这个问题可以通过initrd机制解决,它允许在装载实际的root文件系统之前先使用RAM文件系统。除了上述两个原因,引入initrd还可以解决内核的动态合成问题。(详见参考资料一。)

不过我们应该注意到,init在整个启动过程中并不是从来就有的,它可以说是一个插件,为了解决以上问题,而被加入启动过程,象图一所示,Linux系统在启动时也可以不选择它。

 

为什么要引入initrd
Linux
启动过程中肯定要载入内核镜像,在此过程中有些要素必须考虑:

首先,内核镜像不能太大。由于受到各种硬件和兼容性的限制,Linux的内核镜像不能太大,但是这并不容易做到。Linux内核的核心部分本身就不小了;而且还必须加入会使用到的驱动程序。

其次,要支持尽可能多的硬件设备。我们在启动过程中有一件重要工作:挂载root文件系统,因为进一步的数据和应用软件都在其上,所以我们的内核必须能够访问root文件系统。对于一般用户,如果他们使用IDE硬盘上的ext2文件分区作为root文件系统,不会有什么问题。因为不管是IDE硬盘还是ext2文件系统,它们的驱动肯定会包含在内核镜像自身里面。但是,确实存在一些特殊情况:比如说我们希望发行Linux 统的安装光盘,那么对光盘的驱动,就不一定包含在内核里面了。(有人可能要奇怪了,咦,光盘中的内核镜像不都已经读进来了吗,怎么内核还访问不了光盘呢?注意,读入内核镜像的是 Boot Loader ,内核并不具备 Boot Loader 的功能。)如果没有光盘的驱动,我们又怎么把光盘里的软件包安装到用户的计算机里呢?把驱动程序预先编译到内核里?听起来还不错,可是如果我们除了光盘还有一些其它的安装介质,那么所有这些驱动就会让内核镜像庞大不堪。

而且,还有更严重的问题,各种不同的驱动程序很有可能会发生冲突,特别是以前ISA设备占市场主导地位的时候,这种冲突简直难以避免。

那时的解决办法是发行商提供预先编译好的支持各种设备的不同内核,把每个内核放进一张软盘,随发行包一起交给用户,用户自己选择装有合适内核的软盘进行引导。或者给用户提供制作引导盘的工具,让用户在安装前制作自己的启动盘。当然,哪一种办法都不能让人满意。

唯一的希望在于使用模块化机制。在内核启动的时候调用相应的模块加载驱动程序,然后访问root文件系统。无论是通过内核对设备做进一步的分析还是直接从用户那里得到配置信息,先配置再加载模块的办法,都能有效地避免冲突的发生。

除了在安装的时候需要在挂载root文件系统之前调用相应的模块之外,在完成安装的系统上,我们可能仍然需要在挂载root文件系统之前调用一些模块。这主要是为给计算机进行配置——一般都要针对不同的计算机进行内核配置。

理想情况下,用户按照自己的实际情况配置编译文件,重新编译内核,一步步完成这种工作。但是没有几个用户喜欢这种冗长并且极易出现错误的工作。而且编译和生成内核需要相应的工具,可是大部分用户不需要这些工具。

在安装的过程中可以直接编译一个整体式的内核,但这并不能很好的解决问题:首先,所有的编译工具还需要,其次,编译过程中出现差错导致无法完成任务的概率太大了。所以,我们仍然要使用模块机制:模块机制很可靠,出了错误也只不过不加载对应的模块而已,不会使整个任务失败。而载入模块,象前面说的,也是在挂载root文件系统之前就要得到模块的。

基于以上理由,Linux引入了initrd机制。

 

initrd做什么
initrd
允许系统在启动的时候载入一个RAM盘,这个RAM盘可以被当作一个root文件系统,程序可以在其上运行。(有两重含义,第一,程序在上面;第二,程序的文件系统环境也在上面。)在此之后,可以从别的设备上挂载一个新的root文件系统,先前的root文件系统(initrd)就会被移动到一个目录上去,最终被卸载掉。

为什么要使用RAM盘呢?首先,使用RAM盘能方便的支持以后可能发生的变化;另外,也是为了保持 Boot Loader 工作尽可能的简单。在系统引导时,除了内核镜像之外,Boot Loader把所有相关的信息作为一个文件读入内存,内核在启动中将该文件作为一段连续的内存块看待。也就是把它当作RAM盘来 使用了。正因为如此,这种机制被称作初始 RAM initial RAM Disk,缩 写成 initrd

initrd主要用来把系统的启动划分为两个阶段:初始启动的内核只需保留最精简的驱动程序最小集,此后,在启动必须加载附加的模块时,从initrd中加载。

initrd进行的操作
使用initrd的时候,典型的系统启动的流程变为:

Boot Loader读入内核镜像以及initrd文件

内核将initrd文件转成普通RAM盘,并且释放掉initrd文件占用的内存。

initrd被当作root文件系统,以可读可写(readwrite)方式安装。

/linuxrc被执行(它可以是任何可执行文件,包括脚本在内;它以uid0身份执行,基本上能完成所有init程序可以做的工作)

linuxrc安装实际root文件系统

linuxrc通过pivot_root系统调用将root文件系统放置在root目录下。

常用的启动流 程(比如调用/sbin/init)开始执行。

卸载initrd文件系统。

注意,这是一个典型流程。其实initrd机制可以通过两种方式使用:要么就是作为一个普通的root文件系统使用,这样的话第5、第6两个步骤可以被略过,直接执行/sbin/init( 们的试验系统就是利用这种方法);要么作为一个过渡环境使用,通过它内核可以继续装载实际root文件系统

阅读(2631) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~