Linux根文件系统制作

来自华清远见研发中心
跳转至: 导航搜索

实验原理

文件是计算机系统的软件资源,操作系统本身和大量的用户程序、数据都是以文件形式组织和存放的,对这些资源的有效管理和充分利用是操作系统的重要任务之一。本章介绍文件和文件系统的概念,并对操作系统的文件管理功能给予简要说明。

磁盘的物理组织

文件系统主要完成对磁盘上的数据和程序进行管理,所以首先需要了解磁盘(硬盘)的结构。
磁盘又叫硬盘,由一组盘片组成。每个盘片的上下两面都涂有磁粉,磁化后可以存储信息数据。每个盘片的上下两面都安装有磁头。磁头被安装在梳状的可以做直线运动的小车上以便寻道。每个盘面被格式化成有若干条同心圆的磁道,并规定最外面的磁道是0磁道,次外层是1磁道。每个磁道又被分成若干个扇区,并顺序排为1号扇区、2号扇区,等等。通常,一个扇区可以储存512字节的二进制信息位。这也是CPU进行磁盘I/O操作时能够读出和写入的最小单位。每个盘面上的同号磁道组成一个柱面,也就是说每个盘面的0号磁道组成0号柱面,所有的1号磁道组成1号柱面,等等。硬盘的结构如图所示。

54-1-1-(1).png

在Linux操作系统中,内核采用的方法是把物理磁盘抽象为逻辑磁盘来管理文件系统。所谓逻辑磁盘是把物理磁盘按照磁头号、磁道号、扇区号以及盘面号划分成磁盘块的线性数组,也叫线性序列。例如:把1号盘面0号磁道的0号扇区定义为0号磁盘块;把1号盘面0号磁道的1号扇区定义为1号磁盘块等等;当然一个磁盘块可以包含多个扇区,一般扇区数是2的整次幂。显然,当把实际的磁盘看成是磁盘块的线性数组时,就把物理磁盘存储数据的实际地址(即磁道号、扇区号以及盘面号)隐藏起来。因此呈现在系统高层面前的已经不是物理磁盘,而是一个经过加工以后的逻辑磁盘。图8.2给出了逻辑磁盘的结构示意图,它比物理硬盘的结构要简单的多。当系统执行磁盘I/O操作时,系统给出试图访问的逻辑磁盘块号。由设备驱动程序根据该块号计算出物理磁盘的磁道号、磁头号以及扇区号,然后启动硬盘把磁头向前或向后移动到相应的柱面,这就是所谓的寻道。寻道是磁盘I/O操作中最为耗时的一个操作。一旦磁头找到磁道,并且相应的扇区转到磁头下面,数据传输就开始。

文件和目录

文件是一个具有符号的一组相关联元素的有序序列。文件可以包含范围非常广泛的内容。系统和用户都可以将具有一定独立功能的程序模块、一组数据或一组文字命名为一个文件。在电脑里看见的东西都叫文件。文件是以单个名称在计算机上存储的信息集合。文件可以是文本文档、图片、程序等等。文件通常具有三个字母的文件扩展名,用于指示文件类型。
文件有很多种,运行的方式也各有不同。一般来说我们可以通过文件名来识别这个文件是哪种类型,特定的文件都会有特定的图标,也只有安装了相应的软件,才能正确显示这个文件的图标。

文件的分类

在计算机系统中存放着大量的文件,它们有着不同的内容、用途和形式。 为了便于对文件进行在理合加工,通常把众多的文件从不同的角度进行分类。下面介绍几种经常使用的文件分类方法。 按文件的创建角度,文件分为:

  • 系统文件:即由操作系统创建的文件。这些文件包含着操作系统执行的程序和处理的数据。系统文件仅供操作系统使用,不对用户开放。
  • 用户文件:即由用户创建的文件。这些文件包含的是用户的信息,如用户的程序、数据和其他各种形式的信息。
  • 库文件:即由系统创建、供系统和用户使用的文件。它们是一些由标准函数或子程序及常用的应用程序组成的文件。库文件允许用户调用,但是不允许用户修改。在某些系统中,允许用户通过系统向库文件中添加信息。

按文件的读取权限,文件可以分为:

  • 只读文件:只允许对文件进行读操作,而不允许写操作的文件。
  • 读写文件:指既可以进行读操作,又可以写操作的文件。
  • 可执行文件:指只可以调入到内存中执行,而不能对它们进行读写操作的文件。
  • 不保护文件:这种文件不作任何保护,所有用户都可以使用。

按文件在系统中的信息流向,文件分为:

  • 输入文件:这种文件只能从输入设备中读入到内存,如读卡器上的文件。
  • 输出文件:这种文件只能从系统写入到输出设备中,如打印机上的文件。
  • 输入/输出文件:这种文件既可以从输入设备中读取,又可以向输出设备写入,如磁盘上的文件。

按文件信息的逻辑结构,文件分为:

  • 流文件:以字符为基本单位,按照一定顺序组成的文件。文件内的信息就是一连串的字符,不再划分结构。它使用结束符来标志文件的结束。
  • 记录文件:把文件内的信息划分成多个记录,记录是文件组织和操作的基本单位。记录文件可以分为下面两种:
  • 文本文件:即由字符代码组成的文件。文本文件可以直接显示在屏幕上,或者在打印机上打印,也可以使用编辑器进行编辑。
  • 二进制文件:即由二进制数据组成的文件,如可执行程序、图像文件、声音文件等。二进制文件不能直接显示或打印。

目录

目录是一类特殊的文件,利用它可以构成文件系统的分层树型结构。如同普通文件那样,目录文件也包含数据;但目录文件与普通文件的差别是,核心对这些数据加以结构化,它是由成对的“i节点号/文件名”构成的列表。

  • i节点号是检索I节点表的下标,i节点中存放有文件的状态信息。
  • 文件名是给一个文件分配的文本形式的字符串,用来标识该文件。在一个指定的目录中,任何两项都不能有同样的名字。

每个目录的第一项都表示目录本身,并以“.”作为它的文件名。每个目录的第二项的名字是“..”,表示该目录的父目录。当把文件添加到一个目录中的时候,该目录的大小会增长,以便容纳新文件名。当删除文件时,目录的尺寸并不减少,而是核心对该目录项做上特殊标记,以便下次添加一个文件时重新使用它。

Linux文件系统采用带链接的树形目录结构,即只有一个根目录(通常用“/”表示),其中含有下级子目录或文件的信息;子目录中又可含有更下级的子目录或者文件的信息。这样一层一层地延伸下去,构成一棵倒置的树,如图所示。

54-1-4-(1).png

在目录树中,根节点和中间节点都必须是目录,而普通文件和特别文件只能作为“叶子”出现。当然,目录也可以作为叶子。

文件系统

文件系统指文件存在的物理空间。在Linux系统中,每个分区都是一个文件系统,都有自己的目录层次结构。Linux的最重要特征之一就是支持多种文件系统,这样它更加灵活,并可以和许多其它种操作系统共存。由于系统已将Linux文件系统的所有细节进行了转换,所以Linux核心的其它部分及系统中运行的程序将看到统一的文件系统。

大部分UNIX文件系统种类具有类似的通用结构,即使细节有些变化。其中心概念是超级块superblock, i节点inode, 数据块data block,目录块directory block, 和间接块indirection block。超级块包括文件系统的总体信息,比如大小(其准确信息依赖文件系统)。i节点包括除了名字外的一个文件的所有信息,名字与i节点数目一起存在目录中,目录条目包括文件名和文件的i节点数目。i节点包括几个数据块的数目,用于存储文件的数据。i节点中只有少量数据块数的空间,如果需要更多,会动态分配指向数据块的指针空间。这些动态分配的块是间接块;为了找到数据块,这名字指出它必须先找到间接块的号码。

Linux支持多种操作系统,其实现机制我们在后面会讲到。

虚拟文件系统

Linux系统允许众多不同种类的文件系统共存,如ext3、vfat等。通过使用同一套文件I/O系统调用,即可对Linux中的任意文件进行操作,而无需考虑其所在的文件系统的具体格式。此外,Linux还支持跨文件系统的文件操作,即对文件的操作可以跨文件系统进行。如图8.3所示。实现这种操作的机制正是虚拟文件系统。

54-1-6-(1).png

虚拟文件系统概述

Linux文件系统分为三个部分,第一部分是Virtual File System Switch(VFS),它是Linux文件系统对外的接口,任何要使用文件系统的程序都必须经由这层接口来使用它。另外两部分是属于文件系统的内部实现,分别是cache和真正的文件系统(例如Ext3,VFAT等)。

虚拟文件系统是Linux内核中的一个软件抽象层,它一方面用于给用户空间的程序提供文件系统接口,另一方面还提供了内核中的一个抽象功能,它通过一些数据结构及其方法向实际的文件系统提供接口,实现不同文件系统在Linux中共存。系统中所有文件系统不旦依赖于VFS共存,同时也要依靠VFS协同工作。

为了能支持各种文件系统,VFS定义了所有文件系统都必须支持基本的、概念上的接口和数据结构,例如超级块、节点、文件操作函数入口等。换句话说,一个实际的文件系统要想被Linux支持,就必须提供一个符合VFS标准的接口,这才能与VFS协同工作。VFS不是实际的操作系统,它只是一种转换机制,仅存在于内存中,不存在于任何外存空间。图8.4显示了VFS在内核中与实际的文件系统的协同关系。

54-1-7-(1).png

概述的说,VFS主要提供以下一些功能:

  • 记录可用的文件系统类型;
  • 将设备与对应的文件系统相联系;
  • 处理一些面向文件的通用操作;
  • 涉及针对文件系统的操作时,VFS把它们映射到与控制文件、目录以及inode相关的物理文件系统。

根文件系统开发实验

实验目的

熟悉Linux 文件系统目录结构,创建自己的文件系统,通过NFS 方式测试。

实验平台

华清远见开发环境,FS-MP1A平台;

实验步骤

  1. 导入交叉编译工具链
  2. linux@ubuntu:$ source /opt/st/stm32mp1/3.1-openstlinux-5.4-dunfell-mp1-20-06-24/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
    
  3. 根文件系统制作
  4. 可以从http://busybox.net/downloads/网站下载busybox-1.29.3源码用于制作Linux文件系统,为了方便,已将源码放进了光盘。 安装交叉编译工具链。

    linux@ubuntu:$ sudo apt-get install gcc-arm-linux-gnueabihf
    linux@ubuntu:$ sudo apt-get install g++-arm-linux-gnueabihf
    

    验证开发工具是否安装正确,显示版本信息如下图所示。

    linux@ubuntu:$ arm-linux-gnueabihf-gcc -v

    54-2-3-1.png

    建立源码目录

    linux@ubuntu:$ cd ~
    linux@ubuntu:$ mkdir -p fs-mp1a
    

    将【华清远见-FS-MP1A开发资料\02-程序源码\04-Linux系统移植\01-官方源码】下的busybox-1.29.3.tar.bz2拷贝至该目录。

    linux@ubuntu:$ tar xvf busybox-1.29.3.tar.bz2             //解压源码
    linux@ubuntu:$ cd busybox-1.29.3
    

    配置busybox 源码: 将顶层目录下的Makefile文件中的CROSS_COMPILE字段修改为“arm-linux-gnueabihf-”

    54-2-3-2.png

    可以使用如下命令配置源码

    linux@ubuntu:$ make menuconfig
    
    54-2-3-3.png

    编译源码:

    linux@ubuntu:$ make
    

    安装:
    busybox 默认安装路径为源码目录下的_install

    linux@ubuntu:$ make install
    

    进入安装目录:

    linux@ubuntu:$ cd  _install
    linux@ubuntu:$ ls
    bin  linuxrc  sbin   usr
    


    创建其他需要的目录:

    linux@ubuntu:$ mkdir   dev   etc  mnt   proc   var  tmp   sys   root
    

    添加库:

    将工具链中的库拷贝到_install 目录下:

    linux@ubuntu:$ cp /usr/arm-linux-gnueabihf/lib/ . -a
    

    删除静态库:

    linux@ubuntu:$ rm lib/*.a
    

    添加系统启动文件:

    在etc下添加文件inittab,文件内容如下:

    注意:修改文件均为_install目录下

    etc/inittab

    #this is run first except when booting in single-user mode.
    ::sysinit:/etc/init.d/rcS
    # /bin/sh invocations on selected ttys
    # start an "askfirst" shell on the console (whatever that may be)
    ::askfirst:-/bin/sh
    # stuff to do when restarting the init process
    ::restart:/sbin/init
    # stuff to do before rebooting
    ::ctrlaltdel:/sbin/reboot
    

    在etc下添加文件fstab,文件内容如下:

    /etc/fstab

    #device    mount-point    type    options    dump    fsck order
    proc       /proc          proc    defaults   0             0
    tmpfs      /tmp           tmpfs   defaults   0             0
    sysfs      /sys           sysfs   defaults   0             0
    tmpfs      /dev           tmpfs   defaults   0             0
    
    

    这里我们挂载的文件系统有三个proc、sysfs和tmpfs。

    回到创建的文件系统处,在etc下创建init.d目录,并在init.d下创建rcS文件,rcS 文件内容为:

    etc/init.d/rcS

    #!/bin/sh
    # This is the first script called by init process
    /bin/mount   -a
    
    /sbin/mdev   -s
    
    

    为rcS 添加可执行权限:

    linux@ubuntu:$ chmod a+x init.d/rcS
    

    在etc 下添加profile 文件,文件内容为:

    etc/profile

    #!/bin/sh
    export HOSTNAME=fsmp1a
    export USER=root
    export HOME=root
    export PS1="[$USER@$HOSTNAME \W]\# "
    PATH=/bin:/sbin:/usr/bin:/usr/sbin
    LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
    export PATH   LD_LIBRARY_PATH
    
  5. NFS 测试
  6. 删除原先的/source/rootfs:

    linux@ubuntu:$ sudo rm -rf /source/rootfs
    

    将我们新建的根文件系统拷贝到/source/rootfs目录下

    linux@ubuntu:$ sudo mkdir /source/rootfs
    linux@ubuntu:$ sudo cp _install/* /source/rootfs -a
    

    修改ubuntu主机中的/tftpboot/pxelinux.cfg/01-00-80-e1-42-60-17文件添加nfs启动选项

    # Generic Distro Configuration file generated by OpenEmbedded
    menu title Select the boot mode
    MENU BACKGROUND /splash.bmp
    TIMEOUT 20
    DEFAULT stm32mp157a-fsmp1a-emmc
    LABEL stm32mp157a-fsmp1a-emmc
        KERNEL /uImage
        FDT /stm32mp157a-fsmp1a.dtb
        APPEND root=/dev/mmcblk2p4 rootwait rw console=ttySTM0,115200
    LABEL stm32mp157a-fsmp1a-nfs
        KERNEL /uImage
        FDT /stm32mp157a-fsmp1a.dtb
        APPEND root=/dev/nfs nfsroot=192.168.11.251:/source/rootfs ip=dhcp rootwait rw earlyprintk console=ttySTM0,115200
    

    上述配置中共有两个启动项分别为stm32mp157a-fsmp1a-emmc、stm32mp157a-fsmp1a-nfs。其中stm32mp157a-fsmp1a-emmc选项为正常启动配置;stm32mp157a-fsmp1a-nfs为nfs挂载方式,这里需要注意的是nfsroot=192.168.11.251部分的ip需要根据ubunut主机的实际ip填写。

    重新启动开发板,选择nfs启动选项。

    54-2-3-4.png

    查看是否能够正常挂载,功能是否正常

    54-2-3-5.png

制作根文件系统镜像

上小节已经制作好了根文件系统,并且从NFS已经成功启动。本小节将制作一个根文件系统镜像用于后续的固化和烧录。

  1. 制作ext4格式的文件系统
  2. 在ubuntu中制作一个EXT4空文件, 此处设则为300M大小,由于安装的软件较多时,文件系统会很大,用户可以根据情况自行更改。

    linux@ubuntu:$ dd if=/dev/zero of= fsmp1x_rootfs.ext4 bs=300M count=1
    linux@ubuntu:$ sudo mkfs.ext4 fsmp1x_rootf.ext4
    
  3. 复制文件系统
  4. 将上小节我们移植完成的跟文件系统中所的文件夹都fuubuntu18_rootfs.ext4文件挂载到临时目录/mnt,并拷贝文件系统。

    linux@ubuntu:$ sudo mount -o loop fsmp1x_rootf.ext4 /mnt
    

    如果我们已经制作了前面的文件系统则直接拷贝/source/rootfs/下的文件即可

    linux@ubuntu:$ sudo cp /source/rootfs/* /mnt -a
    

    如果我们之前没有编译制作文件系统也可以将【华清远见-FS-MP1A开发资料\02-程序源码\04-Linux系统移植\02-移植好的系统镜像文件】下的rootfs.tar.xz文件导入到虚拟机中,使用我们已经移植好的跟文件系统进行制作。

    linux@ubuntu:$ sudo tar -xvf rootfs.tar.xz -C /mnt
    
  5. 卸载挂载的fsmp1x_rootf.ext4文件
  6. linux@ubuntu:$ sudo umount /mnt
    

    此时跟文件系统镜像就制作完成了。可以将这个文件导出到windos下烧录到开发板中运行。

  7. 修改烧录文件
  8. 如果想要烧录到开发板那么就需要修改,烧写文件。这里以eMMC启动的trusted镜像为例来说明。其它启动的修改方法也类似。

    修改flashlayout_fs-mp1a-weston\trusted下的FlashLayout_sdcard_stm32mp157a-fsmp1a-trusted.tsv文件将Id为0x23的rootfs分区镜像名由fs-mp1a-weston-openstlinux-weston-fsmp1a.ext4修改为fsmp1x_rootf.ext4。按照《STM32CubeProgrammer烧写方式》章节进行烧录即可。

    54-3-1.png