参考:
https://mp.weixin.qq.com/s/j5Yy-ImpUz2_s1zLzMFGTQ
https://mp.weixin.qq.com/s/gRRdXJE388ghHWSpRShTfQ
文件系统可以说是嵌入式中的一大块,也是绕不过的一部分。之前我对文件系统认知一直停留在在U盘格式的理解上,直到接触了嵌入式Linux才发现这里面大有文章,以Linux启动挂载根文件系统为例,这个文件系统可以是真正的存储设备上的文件系统,也可以是网络文件系统,甚至可以开辟一段内存,虚拟出来一个文件系统,这些在一开始接触嵌入式Linux开发的时候就算讲到了讲的也不会很深,我之前跟着某点教程走了一遍之后脑子里树立起来了这个文件系统的概念,但是感觉还是模模糊糊,后来陆陆续续看了一些文章还有视频,才慢慢有了较为清晰的认识。
了解了这些文件系统相关的知识,对理解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卡文件系统
包括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
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
中通过指定以下环境变量来指定。
tootfstype
= jffs2 , yaffs2, squashfs , ubifs 等 。
根文件系统指定在flash上的话,需要指定分区。
mtdparts
环境变量 指定flash分区表。
内核中必须有mtd驱动才可以支持识别分区表。
推荐教程
上面提到的文件系统教程链接
链接:https://pan.baidu.com/s/1izJq1YETQO2UClwmUZC99Q 提取码:1quy