《学习MakerootFS.ppt》由会员分享,可在线阅读,更多相关《学习MakerootFS.ppt(20页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、跟我一起学习跟我一起学习Make rootFS详解如何制作根文件系统详解如何制作根文件系统Author:某六神仙童E-Mail:Date:2014/11/某日目录目录什么是rootfsrootfs的分类什么是FHS构建rootfs什么是什么是rootfs 什么是什么是fs(file system)这又是一个老生常谈的话题,很多内核爱好者,或者是Linux高手,都曾经为之付出过很多的努力。那么要想弄明白究竟什么是rootfs,还得先从根本概念入手,究竟什么是fs(file system)?用官话解释为:“文件系统是对一个存储设备上的数据和元数据进行组织的机制。这种机制有利于用户和操作系统的交互。
2、”这一切源于类UNIX系统的一个特性:“在 UNIX 传统中,它使用文件 I/O 机制管理硬件设备和数据文件。”Linux内核中针对内核中针对fs的具体实现,使用的具体实现,使用了了VFS这样的优秀模型机制,用以承载从这样的优秀模型机制,用以承载从用户空间到内核空间的具体功能的调用和用户空间到内核空间的具体功能的调用和实现。实现。1,用户空间中,提供了文件访问的系,用户空间中,提供了文件访问的系统调用接口;统调用接口;2,内核空间中,内核空间中,VFS完成了从用户空完成了从用户空间接收命令和数据,进行分析转发给具体间接收命令和数据,进行分析转发给具体文件系统的的功能,相当于转换器;文件系统的的
3、功能,相当于转换器;3,具体文件系统,提供供给,具体文件系统,提供供给VFS使用使用的标准接口,用来承接来自用户空间的各的标准接口,用来承接来自用户空间的各种系统调用命令的数据,以及根据命令和种系统调用命令的数据,以及根据命令和数据完成具体功能。数据完成具体功能。什么是什么是rootfs 根文件系统根文件系统在明白了什么是fs的基础上,再来看看rootfs。相比其他实际文件系统,rootfs与它们之间没有什么区别,也是一种文件系统;但相比其他实际文件系统,rootfs又是特殊的,特殊在于:它是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导启动程序
4、会在根文件系统挂载之后从中把一些初始化脚本(如rcS,inittab)和服务加载到内存中去运行。既然,rootfs是在内核启动时挂载的第一个文件系统,原因何在?实在是因为该文件系统 VFS 的关系太过密切,如果说 ext2/ext3 是 Linux 的本土文件系统,那么 rootfs 则是 VFS 存在的基础。一般文件系统的注册都是通过 module_init 宏以及 do_initcalls()函数来完成,但是 rootfs 的注册却是通过 init_rootfs()这一初始化函数来完成,这意味着 rootfs 的注册过程是 Linux 内核初始化阶段不可分割的一部分。init_rootfs
5、()通通过调用用 register_filesystem(&rootfs_fs_type)函数来完成函数来完成 rootfs 文件系文件系统注册,注册,注册之后的注册之后的 file_systems 链表表结构如构如右右图所示。所示。rootfs的分类的分类rootfs一直以来都是所有类Unix操作系统的一个重要组成部分,也可以认为是嵌入式Linux系统区别于其他一些传统嵌入式操作系统的重要特征,它给 Linux带来了许多强大和灵活的功能,同时也带来了一些复杂性。我们需要清楚的了解根文件系统的基本结构,以及细心的选择所需要的系统库、内核模块和应用程序等,并配置好各种初始化脚本文件,以及选择合适
6、的文件系统类型并把它放到实际的存储设备的合适位置,如下列出几中较常用的系统类型:1)jffs2:日志闪存嵌入式系统文件系统版本2(Journalling Flash FileSystem v2)。主要用于NOR型闪存,基于MTD驱动层,特点是:可读写的、支持数据压缩的、基于哈希表的日志型文件系统,并提供了崩溃/掉电安全保护,提供“写平衡”支持等。缺点主要是当文件系统已满或接近满时,因为垃圾收集的关系而使jffs2的运行速度大大放慢。制限:jffsx不适合用于NAND闪存主要是因为NAND闪存的容量一般较大,这样导致jffs为维护日志节点所占用的内存空间迅速增大,另外,jffsx文件系统在挂载时
7、需要扫描整个FLASH的内容,以找出所有的日志节点,建立文件结构,对于大容量的NAND闪存会耗费大量时间。2)yaffs:Yet Another Flash File System,很个性的名字,包含Ver2.0版本,是专为嵌入式系统使用 NAND型闪存而设计的一种日志型文件系统。与jffs2相比,它减少了一些功能(例如不支持数据压缩),所以速度更快,挂载时间很短,对内存的占用较小。另外,它还是跨平台的文件系统,除了Linux和eCos,还支持WinCE,pSOS和ThreadX等。rootfs的分类的分类(2)yaffs/yaffs2自带NAND芯片的驱动,并且为嵌入式系统提供了直接访问文件
8、系统的API,用户可以不使用Linux中的MTD与VFS,直接对文件系统操作。当然,yaffs也可与MTD驱动程序配合使用。yaffs与 yaffs2的主要区别在于,前者仅支持小页(512 Bytes)NAND闪存,后者则可支持大页(2KB)NAND闪存。同时,yaffs2在内存空间占用、垃圾回收速度、读/写速度等方面均有大幅提升。3)Cramfs:Compressed ROM File System,压缩的ROM文件系统。是Linux的创始人 Linus Torvalds参与开发的一种只读的压缩文件系统。它也基于MTD驱动程序。在cramfs文件系统中,每一页(4KB)被单独压缩,可以随机页
9、访问,其压缩比高达2:1,为嵌入式系统节省大量的Flash存储空间,使系统可通过更低容量的FLASH存储相同的文件,从而降低系统成本。制限:只读属性是它的一大缺陷,使得用户无法对其内容对进扩充。4)NFS:Network File System,网络文件系统。由Sun开发并发展起来的一项在不同机器、不同操作系统之间通过网络共享文件的技术。在嵌入式Linux系统的开发调试阶段,可以利用该技术在主机上建立基于NFS 的根文件系统,挂载到嵌入式设备,可以很方便地修改根文件系统的内容。什么是什么是FHS既然我们已经知道,rootfs对于内核启动是如此重要,那么对于一个rootfs而言,其构成有没有规则
10、可以参照呢?答案是肯定的。这就是所谓的FHS(Filesystem Hierarchy Standard)标准。该标准规定了根目录下各个子目录的名称及其存放的内容:目目录名名存放的内容存放的内容/bin必备的用户命令,例如ls、cp等/sbin必备的系统管理员命令,例如ifconfig、reboot等/dev设备文件,例如mtdblock0、tty1等/etc系统配置文件,包括启动文件,例如inittab等/lib必要的链接库,例如C链接库、内核模块/home普通用户主目录/rootroot用户主目录/usr/bin第三方用户程序,例如find、du等/usr/sbin第三方管理员程序,例如c
11、hroot、inetd等/usr/lib第三方软件依赖的库文件/var守护程序和工具程序所存放的可变文件目录,例如日志文件/proc用来提供内核与进程信息的虚拟文件系统,由内核自动生成目录下的内容/sys用来提供内核与设备信息的虚拟文件系统,由内核自动生成目录下的内容/mnt文件系统挂接点,用于临时安装文件系统/tmp临时性的文件,重启后将自动清除构建完整构建完整rootfs按照FHS的标准,我们来构建一个rootfs,基本上就是在按照上一页的表中所述及的目录结构来进行的。基于这样的目录结构,建立完整的目录内容,基本上所需要的过程是:编译安装busybox,生成/bin、/sbin、/usr/
12、bin、/usr/sbin目录 利用交叉编译工具链,构建/lib目录 手工构建/etc目录 手工构建最简化的/dev目录 创建其它空目录 配置系统自动生成/proc目录 利用udev构建完整的/dev目录 制作根文件系统的jffs2映像文件构建完整构建完整rootfs 编译编译/安装安装busybox编译/安装busybox的目的,是为了构建出四个基础目录:/bin、/sbin、/usr/bin、/usr/sbin。由FHS的规定可知,这几个目录下存放的是Linux常用命令的二进制文件。对于从无到有的创建,这几百个命令,自己动手实现之,我勒个囧rz于是乎,便需要祭出busybox这个利器,来解
13、决这个问题。1)下载源码:2)解压并手动修改Makefile满足交叉编译条件:ARCH?=arm CROSS_COMPILE?=arm-linux-export INSTALL_PATH?=/yourspecifedpath 3)make menuconfig 来配置busybox4)make and make install安装完成之后的busybox本身大小不到800KB!注:busybox以它娇小的身躯容纳了数以百计的命令代码,实在是让人佩服不已,其不愧嵌入式系统瑞士军刀之美誉。据说,busybox的作者身患绝症,这更让人钦佩GNU开源软件的作者们。构建完整构建完整rootfs 交叉编译
14、链中的交叉编译链中的/lib这是关于C库函数的一个话题。我们都知道,C语言实现的可执行文件,少不了会调用各种库函数,so,文件系统里必然少不了C库。如果手工去实现For ARM的C库的话,囧rz,你弄死我吧这时,自然就想到了交叉编译工具链的事情来原来,交叉编译工具链的三大组成已经提供给我们了巨大的财富:交叉编译器、For ARM的C库和二进制工具。Bingo!只需要拷贝过来即可。但拷贝也是需要头脑滴来看看这个库里都有啥兵器:目标文件,如crtn.o,用于gcc链接可执行文件 libtool库文件(.la),在链接库文件时这些文件会被用到,比如他们列出了当前库文件所依赖的其它库文件,程序运行时无
15、需这些文件 gconv目录,里面是各种链接脚本,在编译应用程序时,他们用于指定程序的运行地址,各段的位置等 静态库文件(.a),例如libm.a,libc.a 动态库文件(.so、.so.0-9*)动态链接库加载器、其它目录及文件很显然,我们需要的是第4项、第5项和第六项。构建完整构建完整rootfs 手工构建手工构建/etc目录目录针对/etc目录的特点,即使最小的系统也一定会运行一号进程init,所以我们至少要手工编写其主配置文件inittab。需要注意的是busybox的inittab文件的语法、语义与传统的SystemV的inittab有所不同。手工编写一个最简单的inittab如下:
16、:sysinit:/etc/init.d/rcS:askfirst:-/bin/sh:ctrlaltdel:/sbin/reboot:shutdown:/bin/umount-a r手工编写最简单的脚本程序文件/etc/init.d/rcS如下:#!/bin/shifconfig eth0 修改shell脚本文件/etc/init.d/rcS的权限,以使其可被执行:#chmod a+x/etc/init.d/rcS构建完整构建完整rootfs 手工构建最小手工构建最小/dev目录目录通常,/dev下挂载着几百个之巨的设备文件,通过ls命令可以一览无余,那我们的rootfs中也需要逐个手工创建么
17、?答案是:审时度势,看看再说。一般内核启动到挂载根文件系统,总是需要几个特定的设备文件,那就来观察一下内核启动过程再说:通过这个Warning,可以看出来内核已经成功挂载根文件系统,但却未能成功启动第1个用户进程init。通过错误消息“unable to open an initial console”搜索内核源代码,找到init/main.c文件。然后定位错误log的位置,从而定位错误的原因:不能打开/dev/console。本着COPY的原则,在运行正常的Target上得到设备的属性:#ls-l/dev/consolecrw-1 root root 5,1 2014-11-19 08:40
18、/dev/console依葫芦画瓢:#mknod console c 5 1其他缺失的设备,重复上述步骤,直到OK。构建完整构建完整rootfs 利用利用udev构建完整构建完整/dev目录目录其实上一页中构建出来的最小/dev目录,就是聋子的耳朵,摆设而已。不信?你可以插入某个设备尝试一下,比如插入一个U盘,驱动模块毫无疑问可以正确识别设备,但是当要是用它,进行挂载的时候,就蛋疼了找不着设备因为,/dev下就可怜巴巴的两个设备文件节点:console和null,我看你怎么挂手工创建那么几百个设备文件节点,简直就是天方夜谭。一番盘点之后发现,构建/dev目录可以有三种方法:1)创建静态设备文件
19、:需要使用mknod命令事先创建所有设备文件,Are you kidding me?2)使用devfs:在版本之后被废弃,缺点多且明显。3)使用udev(user device),利用了sysfs的特性。这样,决定使用udev来干这件事情。udev 的原理是:操作系统启动时将识别到的所有设备的信息自动导出到/sys目录,然后用户态的应用程序udev根据/sys中的设备信息,自动在/dev目录下创建所有正确的设备文件。因此我们要做的就是:配置自动生成/sys目录下的内容并调用mdev(mdev是busybox中对udev的简化实现)。#ls/sys#mount-tsysfsnone/sys#ls
20、/sysblockclassfirmwarekernelpowerbusdevicesfsmodule#ls/devconsolenull#mdev-s#ls-ldev|wc-l140#ls/dev/sda*/dev/sda/dev/sda1为了保证USB的即插即用性,在之前的rcS脚本中加入:echo/sbin/mdev/proc/sys/kernel/hotplug一番捣鼓之后,U盘可用了!构建完整构建完整rootfs 创建其他空目录创建其他空目录根据FHS的定义,我们通过mkdir命令来手动创建如下的空目录:#mkdir/home/root/proc/sys/tmp/var/mnt这些目
21、录都是rootfs能够完成Linux通常功能的必须目录,所以手工创建之即可。内核根据对应的目录,会向其中自动写入需要的内容。构建完整构建完整rootfs 配置系统自动生成配置系统自动生成/proc目录目录我们的rootfs,到目前为止,能够正常运行了,可不经意间,发现了这样的问题,在终端正常动作之后,使用ps命令显示当前启动的进程,竟然发现输出空空如也!?联想到,ps的机制是通过查看/proc目录中的内容,来获得进程信息,进而就进入到/proc目录下查看其内容。结果发现,囧rz,怎么也空空如也!?!由FHS针对/proc目录的定义,就已经明白了该目录下存放的文件的作用和属性,所以为了能够让ro
22、otfs更好的作用于进程和任务调度这些功能之上,就必须构建该目录机及其内容。根据其特性,其下内容由内核自动生成,那么我们所做的事情就简单了,配置内核,令其自动生成该目录及其内容即可。在/etc/init.d/rcS脚本中追加如下内容:mount-t proc none/procnone参数的意义:通常情况下mount命令应该写为mount t ext2/dev/hdb1/proc。但由于现在挂载的/proc是虚拟文件系统,它不与任何物理硬盘分区相对应,因此在表示物理硬盘分区的位置用占位符none来表示。这样,重启Target板,到终端正常工作之后,再使用ps命令,发现世界竟然如此之美好_构建完
23、整构建完整rootfs 创建其他空目录创建其他空目录根据FHS的定义,我们通过mkdir命令来手动创建如下的空目录:#mkdir/home/root/proc/sys/tmp/var/mnt这些目录都是rootfs能够完成Linux通常功能的必须目录,所以手工创建之即可。内核根据对应的目录,会向其中自动写入需要的内容。构建完整构建完整rootfs 使用使用tmpfs挂载挂载/dev、/tmp、/var目录目录概念说明时间:什么是tmpfs?顾名思义,tmpfs全称temporary file system。是一种基于内存的文件系统,它和虚拟磁盘ramdisk比较类似像,但不完全相同,和ramd
24、isk一样,tmpfs可以使用RAM,但它也可以使用swap分区来存储。而且传统的ramdisk是个块设备,要用mkfs来格式化它,才能真正地使用它;而tmpfs是一个文件系统,并不是块设备,只是安装它,就可以使用了。tmpfs是最好的基于RAM的文件系统。从其概念中,我们可以得到这样一个启示,这种文件系统能够直接使用RAM,这是一个利好。因为,Nand Flash的擦写寿命是有限的,这是个残酷的事实,这样,我们就有必要把需要频繁读写动作的目录挂载为tmpfs,以减少对Nand Flash的读写频率。还是老方法,修改/etc/init.d/rcS脚本,追加:mount-t sysfs none
25、/sysmount-t tmpfs none/devmount-t tmpfs none/varmount-t tmpfs none/tmp构建完整构建完整rootfs 终之章:制作根文件系统映像终之章:制作根文件系统映像根据之前的所有步骤,根文件系统就制作和配置完毕了,最后一步是将其打包为根文件系统映像文件。根据本文Page5的介绍,我们可以将制作好的rootfs打包成各种映像文件。1)jffs:#mkfs.jffs2-n-s 512-e 16KiB d/srcdir o rootfs.jffs2工具依赖:zlib(MTD工具包依赖)库以及MTD工具包2)yaffs:#mkyaffs2image /yourrootfspath/tmp/rootfs.yaffs工具依赖:yaffs2至此,整个能够参与运行,能够支持烧写的rootfs就做成了。当时使用的时候,你可以选择直接将原始的rootfs通过NFS来挂载,也可以将其烧写到NOR或者NAND Flash上去。That is allIt is Q&A Time参考参考URL1,解析 Linux 中的 VFS 文件系统机制2,文件系统层次结构标准3,
限制150内