嵌入式杂谈之文件系统

以下文章来源于于宙 ,作者yz001;

文件系统可以说是嵌入式中的一大块,也是绕不过的一部分。之前我对文件系统认知一直停留在在U盘格式的理解上,直到接触了嵌入式Linux才发现这里面大有文章,以Linux启动挂载根文件系统为例,这个文件系统可以是真正的存储设备上的文件系统,也可以是网络文件系统,甚至可以开辟一段内存,虚拟出来一个文件系统,这些在一开始接触嵌入式Linux开发的时候就算讲到了也不会很深,我之前跟着XXX教程走了一遍之后脑子里树立起来了这个文件系统的概念,但是感觉还是模模糊糊,后来陆陆续续看了一些文章还有视频,才慢慢有了较为清晰的认识。

本文主要概括常用的文件系统,罗列主要的特点,了解了这些文件系统相关的知识,对理解Linux使用也有帮助,因为根目录下的许多主要目录都是基于文件系统虚拟出来的。

嵌入式常用文件系统

这是整个文件系统的思维导图,下面将以这个图展开进行介绍
在这里插入图片描述
查看本机所有文件系统
使用df -ahT命令查看当前系统的所有文件系统
-h显示大小
-T显示文件系统类型
-a打印所有文件系统
在这里插入图片描述

文件系统总体介绍

一、内核生成的文件系统

sysfs与proc文件系统是内核自动生成的文件系统 。
分为两类:
一类文件系统有大小,称为基于存储设备的文件系统。
一类文件系统根本无法查看大小,称为基于逻辑的虚拟文件系统。

二、基于存储设备的文件系统

基于存储设备的文件系统可以分为内存文件系统和flash文件系统和扩展SD卡文件系统和网络文件系统。

三、内存文件系统

内存文件系统包括tmpfs和ramdisk。
tmpfs文件系统是一种临时的文件系统,由linux内核来支持,只需要在内存中指定一个区域,指定最大的大小,就可以直接使用,不需要对内存进行格式化。
ramdisk是将一部分固定大小的内存( RAM )空间模拟出硬盘分区,断电后会丢失。

四、flash文件系统

flash文件系统包括cramfs和squashfs和jffs/jffs2和yaffs/yaffs2和ubifs。
cramfs是只读压缩的文件系统,可以将文件系统进行压缩,提高存储效率。
squashfs是只读压缩的文件系统,相比于cramfs可以支持更大的单个文件大小。
jffs/jffs2是可以读写,压缩的日志闪存文件系统,主要是应用于nor flash。
yaffs/yaffs2是另一种日志闪存文件系统,主要是为nand型flash设计的文件系统,为了应对flash容量的快速增长。
ubifs是作为jffs2的后继文件系统,满足大容量的需求。

五、扩展SD卡文件系统
扩展SD卡文件系统包括FAT32和ext2/ext3。
FAT32是微软专为windows开发的文件系统,在windows上有很好的兼容性。
ext2/ext3是Linux上的日志文件系统,可靠性好,但在windows上支持不太好。

六、网络文件系统
网络文件系统包括NFS和Samba。
NFS是开发板与宿主机进行挂载的文件系统。
Samba是windows与Linux之间的共享机制。

七、虚拟文件系统
虚拟文件系统无法查看大小,称为基于逻辑的虚拟文件系统。
基于逻辑的虚拟文件系统包括进程文件系统和设备文件系统。
进程文件系统在Linux上常用的是procfs文件系统,Linux启动以后自动挂载在/proc目录下。

设备文件系统在Linux上常用的是sysfs文件系统与devfs文件系统,sysfs文件系统在Linux启动以后,自动挂载在sys目录下。
但devfs文件系统在Linux内核2.6以前使用,现在基本被废弃。

八、存储设备

存储设备可以分为内存和外存和网络,外存还可以分为内置和扩展。
内存对应三、内存文件系统。
外存对应四、flash文件系统。
网络对应六、网络文件系统。
内置包括四、flash文件系统与三、内存文件系统。
扩展对应五、扩展文件系统。

九、配置选项

要在嵌入式系统上使用这些文件系统,内核必须支持这些文件系统 。
是在linux内核裁剪的时候进行配置。
在这里插入图片描述
Linux内核虚拟文件系统

目的是为了使用与文件接口统一的操作来完成系统信息管理。
包括procfs 、 devfs 、 sysfs。
内核中首先需要配置支持这三种文件系统
在这里插入图片描述
在这里插入图片描述
procfs是Linux内核信息的抽象文件接口,大量的内核中的信息以及可调参数都被作为常规文件映射到了一个目录树中/proc。
这样我们就可以简单直接的通过echo和cat这样的文件操作命令对系统信息进行查取和调整了。
大量的系统工具也通过procfs来获取内核参数,例如ps、lspci等。

一、procfs文件系统
首先对procfs进行挂载

# -t 是指定文件系统类型 ,第二个参数是挂载设备,因为是内核设备,所以写none,第三个参数是挂载目录
mount -t proc none /proc
# 或者在 /etc/fstab条目下添加
none /proc proc defaults 0 0
在fstab下添加会在开机以后自动挂载

一旦proc卸载掉,那么df命令就无法使用了。
因为df命令实际是去查看/proc/mounts文件来查看信息。
很多命令例如ps都是通过proc目录来查看系统信息。
再查看一下proc目录下的文件: 带数字的表示是进程信息 。
在这里插入图片描述
其他的都是系统信息
cmdline文件表示内核启动参数。
cpuinfo文件表示cpu信息。
meminfo文件表示内存信息。
sys目录表示系统运行相关的信息,包括内核等,但断电后重新上电会再次使用默认设置。

二、tmpfs文件系统
是一种虚拟内存文件系统,使用内存作为存储分区进行文件的临时性存取,掉电会丢失,创建时不需要使用mkfs进行格式化
使用如下命令进行挂载。

# -o 指定大小
mount -t tmpfs none -o size=10M /tmp

所以一般tmp目录都是临时创建的虚拟文件系统。
在这个文件夹下创建的文件断电后会丢失。
所以通常使用这个目录保存应用程序运行时的信息,不用担心丢失。
作用是通过内存的读取速度提高程序效率,延长flash寿命。

三、devfs文件系统

Linux2.6内核以前设备文件的抽象机制:提供了一种类似于文件的方法来管理位于/dev目录下的所有设备。
特殊设备文件/dev/console以及/dev/tty。
/dev目录下的zero以及null是黑洞文件,相当于输入给黑洞文件的信息全部都会消失。
devfs文件系统后来集成到了sysfs文件系统。
devfs缺点: 设备映射不同,没有主/次设备号,不能支持太多设备。

四、sysfs文件系统
Linux内核2.6以后引入sysfs文件系统:挂载于/sys目录下,把实际连接到系统上的设备和总线组织成一个分级的文件。
用户空间的程序也同样可以使用这些信息实现和内核的交互,该文件系统是当前系统上实际设备树的一个直观反映。
这些信息比/dev目录下的信息更为详细与丰富, 准确。
每个设备在sysfs中都有唯一对应的目录。
使用如下命令创建挂载点

## -t 是指定文件系统类型 ,第二个参数是挂载设备,因为是内核设备,所以写none,第三个参数是挂载目录
mount -t sysfs none /sys
# 或者在 /etc/fstab条目下添加
none /sys sysfs defaults 0 0
# 在fstab下添加会在开机以后自动挂载

udev工具是管理热插拔的工具,利用了sysfs提供的信息来实现所有devfs的功能,通过检测设备的插入与拔出,动态的在/dev目录下创建与删除设备文件。

总结:一切皆文件的抽象思想,使得Linux系统的管理变得简单统一。

嵌入式网络文件系统

一、Network FileSystem
通过NFS挂载远程主机目录,访问该目录就像访问本地目录一样。
使用NFS服务能够方便的使各Linux系统之间实现共享。
Samba:在Linux与windows系统之间共享。基于C/S模式,客户端-服务器模式。使用RPC(Remote Procedure Call,远程过程调用)。
RPC定义了一种与系统无关的方法来实现进程间通信。

二、NFS服务安装

# 安装nfs
sudo apt-get install nfs-kernel-server
# 查看使用帮助
sudo server nfs-kernel-server
# 查看nfs服务状态
sudo server nfs-kernel-server status
# 启动nfs服务
sudo server nfs-kernel-server start
# 关闭nfs服务
sudo server nfs-kernel-server stop
# 重启nfs服务
sudo server nfs-kernel-server restart
# 重新加载配置文件
sudo server nfs-kernel-server reload
# 强制重新加载配置文件
sudo server nfs-kernel-server force-reload

三、NFS设置
/etc/exports控制着nfs服务器导出的访问目录列表 。
示例/home/yuzhou/linux/nfs *(rw,sync,no_root_squash)规则、

/home/yuzhou/linux/nfs 表示要共享的目录
*表示主机名,或者域名或者ip地址,* 表示允许所有主机访问
(rw,sync,no_root_squash)表示共享参数
rw,表示允许读写
sync,表示实时同步
no_suntree_check,表示不检测是否为共享目录的子目录
no_root_squash,表示root用户拥有所有权限

showmount -a显示所有客户端的ip地址
showmount -e显示所有导出的目录列表
exportfs -r重新加载导出列表

三、开发板使用NFS

确保宿主机关闭防火墙,如果可以连接,也可以不关。
nfs内核支持 , Network FileSystem --> [] NFS Client。
查看开发板kernel是否支持NFS,使用cat /proc/filesystem命令,检查是否有NFS一行,如下图所示。
使用如下命令手动挂载nfs目录。

# -t指定文件系统类型 目标设备 挂载点
mount -t nfs 192.168.1.10:/home/nfs /tmp

更详细的NFS搭建知识请参考:
https://zhuanlan.zhihu.com/p/28556875

initramfs文件系统

内核启动的时候需要挂载根文件系统,所以要在内核镜像中对存储设备进行初始化,但这样会导致内核镜像过大。所以可以使用ramfs文件系统。

一、rootfs、ramfs、ramdisk与tmpfs区别

• rootfs与根文件系统的英文rootfs不同,它是指内核启动的初始根文件系统,内核自身虚拟了一个文件系统,如果这个空间内没有文件系统,就回去查找其他文件系统。
• ramfs是基于内存的文件系统,没有内存大小的限制,会动态增加容量,直至耗尽系统内存,使用的是基于内存的缓存,所以io效率高。
• ramdisk是基于ram的块设备, 占据一块固定的内存,使用mke2fs格式化工具创建文件系统,还需要一个文件系统驱动来读写其中的文件。空间固定导致容量有限,想要写入更多内容需要重新格式化。由于Linux块设备缓冲的特点,所以ramdisk上的数据会被拷贝到内存上进行备份,造成内存浪费。
• ramfs的缺点会因为数据的写入自动增长空间,所以可能导致最后系统所有的内存耗完,所以只有root用户或者被授权的用户允许使用ramfs,但是tmpfs增加了容量的限制,允许用户把数据写入交换分区,允许普通用户使用。

二、initrd与initramfs

• initrd是intramfs之前的设计 。
• 作用都是为了在挂载真正的根文件系统之前将设备驱动,工具以及一些初始化流程先加载到内存中运行。
• initrd基于ramdisk技术,initrd的初始化程序是/linuxrc文件,负责 最终完成真正根文件系统的挂载。我们的Ubuntu上都会有一个boot目录,内核从boot分区找到initrd镜像,然后由initrd镜像完成真正跟文件系统的挂载。在PC上initrd用的比较少,initramfs在嵌入式用的多。
• initramfs的实现设计比initrd更简单,更灵活。是基于ramfs文件系统。不是在内核启动完成以后再从磁盘加载到内存进而挂载,而是构建到内核镜像中,所以内核启动完成以后,直接被拷贝到了rootfs空间,作为初始根文件系统,完成真正根文件系统的挂载。

三、initramfs使用
使用如下命令打包initramfs镜像

# 使用cpio命令进行打包
# -o指输出 -H newc 指定打包格式为newc,这是initramfs必须指定的打包格式
# gzip是将它进行压缩,此处可以压缩也可以不压缩
find .|cpio -o -H newc | gzip > ~/myinitramfs.cpio.gz

使用如下命令进行解压查看

# -i 表示指定文件输入进来 -d表示进行解压
# --no-absolute-filenames表示不解压到宿主机根目录下
zcat hello.cpio.gz | cpio -i -d -H newc --no-absolute-filenames

需要在内核配置中进行设置 General setup -->
在这里插入图片描述
镜像复制路径以内核源码根目录为根目录

总结:Linux内核 --> initrd/initramfs(包含根文件系统的设备驱动) --> Real Root Filesystem

详细的官方描述文档:
内核源码目录下 Documentation/filesysytems/ramfs-rootfs-initramfs.txt

嵌入式flash上的文件系统cramfs与squashfs对比
在这里插入图片描述
嵌入式系统上面为了提高安全性与降低文件系统的空间占用。
文件系统一般设置具有如下两个特点:只读 + 压缩。
squashfs是cramfs的替代品。
cramfs全称compressed ROM filesyatem,主要用于嵌入式Linux系,简单与空间高效。
cramfs最大支持的256MB基本可以满足嵌入式Linux要求,允许的最大文件系统大小为256+16=272MB,必须设置内核的页大小也为4KB,才可以正确读取cramfs文件系统。
cramfs因为是对页进行压缩的,所以查看数据的时候先要知道数据在哪一页才能进行解压缩,这一点要求cramfs不能对元数据进行压缩,否则无法查看元数据,不能进行判断。
ACL是指访问控制列表,可以对文件进行权限管理,在嵌入式系统中基本不需要。
在这里插入图片描述
cramfs的超级块与目录结构不进行压缩,所谓布局与管理相对来说比较简单。
这里说的压缩是指数据一直处于被压缩状态,只有真正使用的时候才会对数据进行解压缩。
cramfs在2013年被linus标记为过时的文件系统,推荐使用aquashfs替代cramfs。
这两个文件系统都是只读文件系统。

嵌入式文件系统jffs/jffs2与yaffs/yaffs2

它们是专门针对闪存的特性进行设计。
flash闪存的类型:是一种非易失性存储器,以块为单元进行擦除和再编程 ,任何flash的器件的写入操作只能在空或者已经擦除的单元内进行,在进行写入操作之前必须执行擦除。
在这里插入图片描述
分为硬件特性,存取特性,以及两种特性决定的结论对比。
XIP是指片内执行功能,代码可以直接存储在flash上面,不需要拷贝到内存。
针对flash设计的两种文件系统对比。
在这里插入图片描述
共性是都是为flash设计的,都是日志文件系统。

yaffs是针对大容量设计的文件系统,所以仅仅支持nand flash。
掉电保护,损耗平衡,垃圾回收都是为了保证数据可靠,提高使用寿命,以及提高存取效率。
挂载时间与内存消耗是重点关注的两个方面。
挂载时间决定了嵌入式系统的启动时间,jaffs2会对整个文件系统进行全部盘扫描,将日志节点扫描出来,在内存中创建文件系统的目录结构。所以挂载时间慢,内存消耗多。
举例说明:
jaffs2挂载16M文件系统需要消耗半分钟,而yaffs2是立即挂载
jaffs2在128M,页大小为512K的文件系统上,大约会消耗4M内存,而yaffs只需要512K字节。
Direct使用:
考虑到文件系统的移植性,yaffs2支持在没有操作系统,没有VFS,没有MTD驱动的情况下,直接使用yaffs2,因为yaffs自带nand flash 驱动,所以移植性,模块性,扩展性更好,已经被移植到UCOSII上。

ramdisk根文件系统

文件系统与操作系统通过某种形式连接起来(内存,flash,网络)。
将内核的指针指向文件系统,读出文件,内核就可以启动成功。
ramdisk称为内存磁盘。

# 设置相关参数
# root表示启动的根文件系统在哪个设备
# 设备信息 ram nfs flash
# init进程是什么,内核启动后的第一个可执行文件 init =
# 内核启动时,使用那个设备作为控制台 console=

root = /dev/ram
initrd=<start_addr>,<size>
init=/linuxrc
console=ttymxc0

内核可以自解压.gz类型的压缩包。

根文件系统类型

了解完以上知识以后我们知道Linux的根文件系统可以设置为flash相关的文件系统或内存相关的文件系统或者网络文件系统。
这在uboot中通过指定以下环境变量来指定。
rootfstype = jffs2 , yaffs2, squashfs , ubifs 等 。
根文件系统指定在flash上的话,需要指定分区。
mtdparts环境变量 指定flash分区表。
内核中必须有mtd驱动才可以支持识别分区表。

猜你喜欢

转载自blog.csdn.net/thisway_diy/article/details/105438088