嵌入式系统实验报告(二)--嵌入式文件系统的构建138352019陈霖坤一实验目的了解嵌入式操作系统中文件系统的类型和作用了解JFFS2文件系统的优点及其在嵌入式系统中的作用掌握利用Busybox软件制作嵌入式文件系统的方法掌握嵌入式linux文件系统的挂载过程二实验内容与要求编译BusyBox,以BusyBox为基础,构建一个适合的文件系统;制作ramdisk文件系统映像,用你的文件系统启动到正常工作状态;研究NFS作为根文件系统的启动过程。
三Busybox介绍BusyBox最初是由Bruce Perens在1996年为Debian GNU/Linux安装盘编写的,其原始构想是希望在一张软盘上能放入一个开机系统,以作为急救盘和安装盘。
后来它变成了嵌入式Linux设备和系统和Linux发布版安装程序的实质标准,因为每个Linux可执行文件需要数Kb的空间,而集成两百多个程序的BusyBox可以节省大量空间。
Busybox集成了包括mini-vi编辑器、/sbin/init、文件操作、目录操作、系统配置等应用程序。
Busybox支持多种体系结构,可以选择静态或动态链接,以满足不同需要。
四linux文件系统文件系统是对一个存储设备上的数据和元数据进行组织的机制,linux文件系统接口设计为分层的体系结构,从而将用户接口层、文件系统实现层和操作存储设备的驱动程序分隔开。
在文件系统方面,linux可以算得上操作系统中的“瑞士军刀”。
Linux支持许多种文件系统,从日志型文件系统到集群文件系统和加密文件系统,而且对于使用标准的和比较奇特的文件系统以及开发文件系统来说,linux是极好的平台,这得益于linux内核中的虚拟文件系统(VFS,也称虚拟文件系统交换器)。
文件结构Windows的文件结构是多个并列的树状结构,不同的磁盘分区各对应一个树。
Linux的文件结构是单个的树,最上层是根目录,其它目录都从根目录生成。
不同的linux发行版集成的功能和界面不同,但文件系统的结构是统一的,一些标准的目录有:/bin二进制可执行命令/dev设备特殊文件/etc系统管理和配置文件/etc/rc.d启动的配置文件和脚本/home用户主目录的基点,比如用户user的主目录就是/home/user,可以用~user表示/lib标准程序设计库,又叫动态链接共享库,作用类似windows里的.dll文件/sbin系统管理命令,这里存放的是系统管理员使用的管理程序/tmp公用的临时文件存储点/root系统管理员的主目录(呵呵,特权阶级)/mnt系统提供这个目录是让用户临时挂载其他的文件系统。
/lost+found这个目录平时是空的,系统非正常关机而留下“无家可归”的文件(windows下*.chk)就在这里/proc虚拟的目录,是系统内存的映射。
可直接访问这个目录来获取系统信息。
/var某些大文件的溢出区,比方说各种服务的日志文件/usr最庞大的目录,要用到的应用程序和文件几乎都在这个目录。
其中包含:/usr/bin众多的应用程序/usr/sbin超级用户的一些管理程序/usr/include linux下开发和编译应用程序所需要的头文件/usr/lib常用的动态链接库和软件包的配置文件/usr/src源代码,linux内核的源代码就放在/usr/src/linux里/usr/local/bin本地增加的命令/usr/local/lib本地增加的库VFSLinux文件系统有两个特性,一个是对文件的操作可以跨文件系统执行,另一个是内核把对所有资源的操作都看做文件操作,不仅是普通文件、目录,还是字符设备、块设备,在linux中都是被当成文件看待。
实现这一特性的关键就是虚拟文件系统(Virtual File System),它是位于实际文件系统上方的一个软件层,使用户空间的程序能够利用这个接口控制不同的文件系统。
VFS有四个主要的数据结构,定义在源码目录的include/linux/fs.h和dcache.h下(只列举涉及整体架构的成员,其余成员限于篇幅不多做展开):superblock:超级块,存储一个已安装的文件系统的控制信息,代表一个已安装的文件系统;每次一个实际的文件系统被安装时,内核会从磁盘的特定位置读取一些控制信息来填充内存中的超级块对象。
一个安装实例和一个超级块对象一一对应。
结构体如下:struct super_block{//fs.h第1240行超级块结构struct list_head s_list;//指向超级块链表的指针......struct file_system_type*s_type;//文件系统类型struct super_operations*s_op;//超级块操作列表......struct list_head s_inodes;//所有节点......#ifdef CONFIG_SMPstruct list_head__percpu*s_files;#elsestruct list_head*s_files;//所有文件#endif......struct list_head s_instances;//同具有该类型文件系统的超级块......};......struct super_operations{//fs.h第1602行超级块操作结构......struct inode*(*alloc_inode)(struct super_block*sb);//该函数在给定的超级块下创建并初始化一个新的索引节点对象......void(*read_niode)(struct inode*);//该函数从磁盘上读取索引节点,并动态填充内存中对应的inode对象的剩余部分......};inode:索引节点,存储了文件的相关信息,代表了存储设备上的一个实际的物理文件。
当一个文件首次被访问时,内核会在内存中组装相应的索引节点对象,以便向内核提供对一个文件进行操作时所必需的全部信息;这些信息一部分存储在磁盘特定位置,另外一部分是在加载时动态填充的。
结构体如下:struct inode{//fs.h第527行节点结构......struct inode_operations*i_op;//索引节点操作表struct file_operations*i_fop;//该索引节点对应文件的文件操作集struct super_block*i_sb;//相关的超级块......};......struct inode_operations{//fs.h第1557行索引节点操作结构......int(*create)(struct inode*,struct dentry*,int,struct nameidata*);//该函数为dentry对象所对应的的文件创建一个新的索引节点,主要是由open()系统来调用struct dentry*(*lookup)(struct inode*,struct dentry*,struct nameidata*);//在特定目录中寻找dentry对象所对应的的索引节点......};dentry:目录项,比如路径/usr/src/linux-headers-3.8.0-33/include/linux/dcache.h,斜杠分隔开的每一项都是目录项,在这个例子中就是usr、src、linux-headers-3.8.0-33、include、linux、dcache.h,引入目录项的概念主要是出于方便查找文件的目的,VFS在遍历路径名的过程中现场将它们逐个解析成目录项。
不同于前面两个对象,目录项没有对应的磁盘数据结构。
结构体如下:struct dentry{//dcache.h第103行目录项机构......struct inode*d_inode;//相关的索引节点struct dentry*d_parend;//父目录的目录项struct qstr d_name;//目录项名字......struct lis_head d_subdirs;//子目录......struct dentry_operations*d_op;//目录项操作列表struct super_block*d_sb;//文件超级块......};......struct dentry_operations{//dcache.h第146行目录项操作结构int(*d_recalidate)(struct dentry*,struct nameidata*);//判断目录项是否有效int(*d_hash)(struct dentry*,struct qstr*);//为目录项生成散列值......};file:文件,是已打开的文件在内存中的表示,主要用于建立进程和磁盘上的文件的对应关系。
它由sys_open()现场创建,由sys_close()销毁。
文件对象和物理文件的关系有点像进程和程序的关系一样。
当我们站在用户空间来看待VFS,我们像是只需与文件对象打交道,而无须关心超级块,索引节点或目录项。
因为多个进程可以同时打开和操作同一个文件,所以同一个文件也可能存在多个对应的文件对象。
文件对象仅仅在进程观点上代表已经打开的文件,它反过来指向目录项对象(反过来指向索引节点)。
一个文件对应的文件对象可能不是惟一的,但是其对应的索引节点和目录项对象无疑是惟一的。
struct file{//fs.h第767行文件结构......struct list_head f_list;//文件对象链表struct dentry*f_dentry;//相关目录项对象struct vfsmount*f_vfsmnt;//相关的安装文件系统struct file_operations*f_op;//文件操作表......};......struct file_operations{//fs.h第1526行文件操作......ssize_t(*read)(struct file*,char__user*,size_t,loff_t*);//文件读操作......ssize_t(*write)(struct file*,const char__user*,size_t,loff_t*);//文件写操作......int(*readdir)(struct file*,void*,filldir_t);//读取目录......int(*open)(struct inode*,struct file*);//文件打开操作......};此外,VFS还关心两个比较重要的结构,向内核注册的文件系统和挂载的文件系统列表:struct file_system_type{//fs.h第1814行注册的文件系统类型const char*name;//文件系统类型名int fs_flags;......struct file_system_type*next;//指向下一个文件类型struct list_head fs_supers;//对应此文件类型的超级块};strruct vfsmoount{//mount.h第52行挂载的文件系统struct list_head mnt_hash;struct vfsmount*mnt_parent;struct dentry*mnt_mountpoint;struct dentry*mnt_root;struct super_block*mnt_sb;struct list_head mnt_mounts;struct list_head mnt_child;atomic_t mnt_count;int mnt_flags;char*mnt_devname;struct list_head mnt_list;};内核支持的文件系统类型在编译时建立,以file_system_type结构体的形式保存,结构体以next成员形成链表(哪怕系统中没有该文件系统的分区),其中fs_supers成员保存了具有本文件系统类型的超级块列表。