ramdisk文件系統的介紹與制作【轉】


轉自:https://blog.csdn.net/silent123go/article/details/52642841

一、文件系統與根文件系統
    1、文件系統
        文件系統是操作系統用於明確存儲設備(常見的是磁盤,也有基於NAND Flash的固態硬盤)分區上的文件的存儲方法和數據結構,即在存儲設備上組織文件的方法。
        看了這個概念如果有些懵,下面用兩個例子來說明。
        a、ext2文件系統
            一個分區格式化成ext2文件系統后,分區里會有三種塊inode、block、super block(當然還有其他類型的塊)。
            Super block: 記錄此文件系統的整體信息,包括inode/block的總量、使用量,以及文件系統的格式和相關信息等;
            Inode: 記錄文件的屬性,一個文件占用一個inode,同時記錄此文件的數據所在的block號碼;
            Block:實際記錄文件的內容,若文件太大時會占用多個block。
            由於每個inode於block都有編號,而每個文件都會占用一個inode,inode內記錄有文件數據放置的block號碼。因此,我們可以知道的是,如果能夠找到文件的inode的話,那么自然就會知道這個文件所放置數據的block號碼,當然也就能夠讀出該文件的實際數據了。這是個比較有效率的做法,因為如此一來我們的磁盤就能夠在短時間內讀取出全部的數據,讀寫性能比較好。

                                                                                         (圖1-1)
        b、Fat文件系統
            我們慣用的U盤(閃存),使用的文件系統一般為FAT格式。FAT這種格式的文件系統並沒有inode存在,所以FAT沒有辦法將這個文件的所有block在一開始就全部讀取出來。每個block號碼都記錄在前一個block當中,讀取它的方式如圖1-2所示。

                                                                                        (圖1-2)
        通過以上兩個例子的說明,我們可以知道,文件系統決定了數據在磁盤上的存儲和訪問方式。不同的存儲介質有着不同的特性,需要選擇適當的文件系統。Norflash一般使用jffs2,Nandflash早期使用的是yaffs2,現在一般使用ubifs,因為隨着技術的進步Nandflash的容量越來越大,yaffs2已經hold不住了。而mmc我們現在使用的是ext4文件系統。需要了解更多不同文件系統的特性,可以閱讀本文的最后一章,記錄了常見文件系統的優缺點。
    2、根文件系統
        根文件系統是一種特殊的文件系統,特殊就在於它必須有目錄結構。
        Linux啟動時,第一個必須掛載的是根文件系統,若系統不能從指定設備上掛載根文件系統,則系統會出錯而退出啟動。成功之后可以自動或手動掛載其他的文件系統。因此,一個系統中可以同時存在不同的文件系統。
        根文件系統之所以在前面加一個”根“,說明它是加載其它文件系統的”根“,既然是根的話,那么如果沒有這個根,其它的文件系統也就沒有辦法進行加載的。它包含系統引導和使其他文件系統得以掛載(mount)所必要的文件。根文件系統包括Linux啟動時所必須的目錄和關鍵性的文件,例如Linux啟動時都需要有init目錄下的相關文件,在 Linux掛載分區時Linux一定會找/etc/fstab這個掛載文件等,根文件系統中還包括了許多的應用程序bin目錄等,任何包括這些Linux 系統啟動所必須的文件都可以成為根文件系統。  

二、linux文件系統結構

    (1)Linux支持多種文件系統,包括ext2、ext3、vfat、ntfs、iso9660、jffs、romfs和nfs等,為了對各類文件系統進行統一管理,Linux引入了虛擬文件系統VFS(Virtual File System),為各類文件系統提供一個統一的操作界面和應用編程接口。
    (2)在嵌入式Linux下,MTD(Memory Technology Device,存儲技術設備)為底層硬件(閃存)和上層(文件系統)之間提供一個統一的抽象接口,即Flash的文件系統都是基於MTD驅動層的。
    (3)使用MTD驅動程序的主要優點在於,它是專門針對各種非易失性存儲器(以閃存為主)而設計的,因而它對Flash有更好的支持、管理和基於扇區的擦除、讀/寫操作接口。

三、ramdisk文件系統介紹
    在 linux 系統中 ,ramdisk 有二種 , 一種(initrd)就是可以格式化並加載, 在 linux 內核 2.0/2.2 就已經支持 , 其不足之處是大小固定 ; 另一種(initramfs)是2.4 的內核才支持 , 通過ramfs 來實現 , 他不能被格式化 , 但用起來方便 , 其大小隨所需要的空間增加或減少 , 是目前 linux 常用的 ramdisk 技術。我們這里講的ramdisk實際上就是initrd,想了解更多initrd和initramfs的區別看我的另一篇文章《initramfs的介紹與制作》。
    RamDisk實際上是從內存中划出一部分作為一個分區使用,換句話說,就是把內存一部分當做硬盤使用,你可以向里邊存文件。
    RamDisk並非一個實際的文件系統,而是一種將實際的文件系統裝入內存的機制,並且可以作為根文件系統。實際上它使用的文件系統是ext2。
    那么為什么要用RamDisk呢?a) 假設有幾個文件要頻繁的使用,你如果將它們加到內存當中,程序運行速度會大副提高,因為內存的讀寫速度遠高於硬盤。況且內存價格低廉,一台PC有128M或256M已不是什么新鮮事。划出部分內存提高整體性能不亞於更換新的CPU。b) ramdisk是基於內存的文件系統,具有斷電不保存的特性,假設你對文件系統做了什么破壞導致系統崩潰,只要重新上電即可恢復。

四、ramdisk文件系統的制作
    1、自己建立根文件系統
        (1)創建根文件系統目錄
            mkdir rootfs  
            cd rootfs
            mkdir root dev etc boot tmp var sys proc lib mnt home usr   
            mkdir etc/init.d etc/rc.d etc/sysconfig  
            mkdir usr/sbin usr/bin usr/lib usr/modules  
            mkdir var/lib var/lock var/run var/tmp
            sudo mknod -m 600 dev/console c 5 1  
            sudo mknod -m 600 dev/null  c 1 3  
            寫成一個腳本,避免每次都要一行行敲,如下
        (2)拷貝交叉編譯工具里面的庫
            比如我使用的交叉編譯工具是arm-none-linux-gnueabi-gcc,先找到該工具的安裝目錄,使用which is命令
            root@silent:/home/mkrootfs# which is arm-none-linux-gnueabi-gcc
            /root/CodeSourcery/Sourcery_G++_Lite/bin/arm-none-linux-gnueabi-gcc
            然后找到相應的動態庫,拷貝到我們的lib目錄。必須加上-d參數,才能把連接拷貝過來。
            cp /root/CodeSourcery/Sourcery_G++_Lite/arm-none-linux-gnueabi/libc/lib/* /home/mkrootfs/rootfs/lib -rfd
        (3)建立etc目錄下的配置文件
            a、拷貝主機etc目錄下的passwd、group、shadow文件到rootfs/etc目錄下。
            b、創建etc/mdev.conf內容為空。
            c、etc/sysconfig目錄下新建文件HOSTNAME(主機名),內容為“jimmy”。
            d、編輯etc/inittab文件,內容如下:
            ::sysinit:/etc/init.d/rcS        #rcS作為系統初始化文件                                 
            console::askfirst:-/bin/sh      #在串口啟動一個登錄會話
            ::restart:/sbin/init  
            ::ctrlaltdel:/sbin/reboot     
            ::shutdown:/bin/umount -a -r  #告訴init在關機時運行umount命令卸載    所有的文件系統,如果卸載失敗,試圖以只讀方式重新掛載。
            ::shutdown:/sbin/swapoff -a  

            注釋:由於默認的內核命令行上有init=/linuxrc, 因此,在文件系統被掛載后,運行的第一個程序是根目錄下的linuxrc。這是一個指向/bin/busybox的鏈接,也就是說,系統起來后運行的第一個程序也就是busybox本身。
            這種情況下,busybox首先將試圖解析/etc/inittab來獲取進一步的初始化配置信息。
            若沒有/etc/inittab這個配置文件,根據busybox的邏輯,它將生成默認的配置。(參考busybox源代碼init/init.c中的parse_inittab()函數。其中,該函數里最重要的一個語句,就是new_init_action(SYSINIT, INIT_SCRIPT, “”), 也就決定了接下去初始化的腳本是INIT_SCRIPT所定義的值。這個宏的默認值是“/etc/init.d/rcS”)。
            e、編輯etc/init.d/rcS文件,並chmod +x 修改文件權限
            #!/bin/sh
            PATH=/sbin:/bin:/usr/sbin:/usr/bin #啟動環境,設置必要的環境變量
            runlevel=S
            prevlevel=N
            umask 022
            export PATH runlevel prevlevel
            echo "----------mount all----------------"
            mount -a   #讀取/etc/fstab,加載文件系統
            #echo /sbin/mdev>/proc/sys/kernel/hotplug
            #mdev –s
            echo "****************Hello jimmy*********************"
            echo "Kernel version:linux-3.18.28"
            echo "***********************************************"
            /bin/hostname -F /etc/sysconfig/HOSTNAME #設置機器名字
            f、編輯etc/fstab
            #device   mount-point     type       option       dump      fsck  
            proc      /proc           proc       defaults     0         0  
            none      /tmp            ramfs      defaults     0         0  
            #mdev     /dev            ramfs      defaults     0         0  
            sysfs      /sys            sysfs      defaults     0         0
            g、編輯etc/profile
            USER="id -un"                    #id -un是打印輸出當前的用戶名,例如:root
            LOGNAME=$USER
            PS1='[\u@\h $PWD]#'              #“[用戶名@主機名 目錄]#”, PS1的值即進入shell后的默認
            PATH=$PATH
            HOSTNAME='/bin/hostname'         #通過/bin/hostname獲取主機名
            export USER LOGNAME PS1 PATH
            echo “-----/etc/profile-------”

            注釋:
            該文件在進入shell的時候調用,也就是說這是用戶相關的.
            與環境變量相關的文件可能還會有/etc/bashrc等,不過這是shell變量,是局部的,對於特定的shell起作用。/etc/profile是全局的,適用於所有的shell。
            注意:若PS1的按如上設置后,進入控制台后,顯示的還是原來的字符,則很有可能是busybox的配置問題:
            make menuconfig
            busybox settings->busybox library tuning->username completion、fancy shell prompts選上。
            重新make即可。
        (4)交叉編譯busybox
            a、首先到busybox官網下載最新的busybox。網址https://busybox.net/
            b、修改busybox源碼根目錄下的Makefile:
            CROSS_COMPILE ?=arm-none-linux-gnueabi-
            ARCH ?=arm                              
            c、make distclean (清除之前生成的文件)
            d、make defconfig (使用默認配置)
            e、make (編譯)
            f、make CONFIG_PREFIX=/home/mkrootfs/rootfs install
            執行完后在rootfs 目錄下會生成目錄bin、sbin 、usr/bin,usr/sbin和文件 linuxrc 的內容。
        (5)編譯安裝內核模塊
            make modules ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
            make modules_install INSTALL_MOD_PATH=/home/mkrootfs/rootfs
        (6)使用工具制作ramdisk文件系統
            下載地址:http://genext2fs.sourceforge.net
            genext2fs -b 4096 -d rootfs ramdisk
            -b是指制作的ramdisk大小為4096K字節 -
            d是指要制作成ramdisk的根文件系統目錄
            最后的ramdisk是制作出來的ramdisk的名字,當然可以改名了。
            gzip -9 -f ramdisk
            將該ramdisk以最優方式壓縮為ramdisk.gz
    2、在一個已經建好的文件系統上進行修改
      1、解壓
      #cd ramdisk.gz所在目錄
      #gunzip ramdisk.gz
      在解壓后,得到文件系統鏡象文件ramdisk, 覆蓋了原來的壓縮文件

      2、鏡象文件掛載
      鏡象文件必須經過掛載后才能看到文件系統中的各個目錄和詳細內容
      #mkdir /mnt/loop
      /mnt/loop 是文件系統要掛載到的目錄
      #mount –o loop ramdisk /mnt/loop

      3、在掛載目錄/mnt/loop下對文件系統進行操作
      #cd /mnt/loop
      根據需要增加、刪減或是修改文件系統的內容

      4、卸裝文件系統
      跳到/mnt/loop目錄外,否則無法卸裝,提示busy
      #cd ramdisk所在目錄
      #umount /mnt/loop

      5、壓縮文件系統
      #gzip –v9 ramdisk /*生成ramdisk.gz壓縮文件

五、ramdisk作為根文件系統的配置
    1、uboot支持ramdisk文件系統
        uboot下需要對bootargs參數進行設置,分為兩種情況
        a、使用mkimage將zImage和ramdisk壓縮成了一個文件
        bootargs=console=ttyS2,57600n8 rw mem=110M@0xc0000000 root=/dev/ram
        b、zImage和ramdisk是分開的
        bootargs=initrd=0xc2000000,0x4000000 root=/dev/ram init=/linuxrc console=ttyS2,57600n8 rw mem=110M@0xc0000000
        意思為從ramdisk啟動,ramdisk壓縮文件起始地址在內存地址0xc2000000處,文件大小為0x4000000。這邊內存的總大小是110M,ramdisk的大小是64M,發現系統啟動時卡在
        Uncompressing Linux... done, booting the kernel.
        找了老半天發現是因為ramdisk設置太大了,改成52M以下就能正常啟動。沒搞明白為什么,估計是不能大於內存的一半。
    2、linux支持ramdisk文件系統
        (1)配置
            a、General Setup ---> [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

            b、Device Drivers ---> [*] Block devices ---> <*> RAM block device support
            (1) Default number of RAM disks
            (65536) Default RAM disk size(kbytes)

            c、File systems ---><*>Second extended fs support
            [*]   Ext2 extended attributes
            [*]   Ext2 POSIX Access Control Lists                                                                              
            [*]   Ext2 Security Labels

            d、修改.config中CONFIG_CMDLINE的定義(若uboot下已經對bootargs做了配置,這步可省略)
            CONFIG_CMDLINE="initrd=0xc2000000,0x4000000 root=/dev/ram rw init=/linuxrc console=ttyS2,57600n8 rw mem=110M@0xc0000000
      
        (2)制作
            a、zImage和ramdisk是分開的
                按照前面的步驟制作好ramdisk.gz,然后使用如下命令制作uImage
                mkimage -A arm -O linux -T kernel -C none -a 0xc0008000 -e 0xc0008000 -n "Linux kernel Image" -d zImage uImage
            b、zImage和ramdisk壓縮成一個文件
                gzip -c9 zImage > zImage.gz
                mkimage -A arm -O linux -T multi -C gzip -a 0xc0008000 -e 0xc0008000 -n "Linux kernel Image" -d zImage.gz:ramdisk.gz firmware.ext2

                mkimage只對兩個參數進行說明。
                -a指的是加載地址
                -e指的是入口地址

                使用mkimage生成內核鏡像文件時,會在內核的前頭加上了64byte的信息,供建立tag之用。bootm命令(bootm xxxx)會首先判斷xxxx這個地址與-a指定的加載地址是否相同。
                如果不同的話會從這個地址開始提取出這個64byte的頭部,對其進行分析,然后把去掉頭部的內核復制到-a指定的load地址中去運行之
                如果相同的話那就讓其原封不同的放在那,但-e指定的入口地址會推后64byte,以跳過這64byte的頭部。

                我們來看看這兩個地址的不同情況:
                1) mkimage -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008040 -n linux-2.6.18.8 -d zImage uImage
                這種情況 ,只能把 uImage download到 30008000的位置上,否則 從0x30008040是啟動不了的.
                原因:如果將uImage(加了頭的鏡像文件)下載到不同於指定加載地址的地方,則會進行上面的操作,將去掉頭部的內核拷貝到指定的加載地址,此時加載地址和入口地址需要是相同的,因為已經沒有鏡像頭了,所以此時入口地址也應該為30008000,而不應該再加上64個字節.
                2) mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008000 -n linux-2.6.18.8 -d zImage uImage
                這種情況download地址隨便. 還是按上面說的,因為將加載地址和入口地址設置成同樣的地址,在下載到任意地址時,將去掉頭部的內核鏡像拷貝到指定加載地址后,可以直接從加載地址開始啟動。
    3、如何啟動系統
        a、zImage和ramdisk是分開的
            按照上述,在uboot下配置好參數bootargs后,執行以下命令即可。
            tftp 0xc2000000 ramdisk.gz
            tftp 0xc0700000 uImage
            bootm 0xc0700000
        b、zImage和ramdisk壓縮成一個文件
            按照上述,在uboot下配置好參數bootargs后,執行以下命令即可。
            tftp 0xc0700000 firmware.ext2
            bootm 0xc0700000

六、常見文件系統介紹
    (1)flash介紹
        不同的flash要選擇相應的文件系統才能提高讀寫效率。要想知道flash適用的文件系統,必須先了解flash的特性。
        Flash(閃存)作為嵌入式系統的主要存儲媒介,有其自身的特性。Flash的寫入操作只能把對應位置的1修改為0,而不能把0修改為1(擦除Flash就是把對應存儲塊的內容恢復為1)。因此,一般情況下,向Flash寫入內容時,需要先擦除對應的存儲區間,這種擦除是以塊(block)為單位進行的。
        閃存主要有NOR和NAND兩種技術。norFlash存儲器的擦寫次數是有限的,NAND閃存則有特殊的硬件接口和讀寫時序。因此,必須針對Flash的硬件特性設計符合應用要求的文件系統。
        一塊Flash芯片可以被划分為多個分區,各分區可以采用不同的文件系統;兩塊Flash芯片也可以合並為一個分區使用,采用一個文件系統。即文件系統是針對於存儲器分區而言的,而非存儲芯片。
    (2)幾種常見的文件系統
        A、JFFS2日志閃存文件系統版本2 (Journalling Flash FileSystem v2)
            JFFS文件系統最早是由瑞典Axis Communications公司基於Linux2.0的內核為嵌入式系統開發的文件系統。JFFS2是RedHat公司基於JFFS開發的閃存文件系統,最初是針對RedHat公司的嵌入式產品eCos開發的嵌入式文件系統,所以JFFS2也可以用在Linux, uCLinux中。
            主要用於NOR型閃存,基於MTD驅動層。
            優點:可讀寫的、支持數據壓縮的、基於哈希表的日志型文件系統,並提供了崩潰/掉電安全保護,提供“寫平衡”支持等。
            缺點:主要是當文件系統已滿或接近滿時,因為垃圾收集的關系而使jffs2的運行速度大大放慢。
            目前jffs3正在開發中。關於jffs系列文件系統的使用詳細文檔,可參考MTD補丁包中mtd-jffs-HOWTO.txt。
            jffsx不適合用於NAND閃存,主要是因為NAND閃存的容量一般較大,這樣導致jffs為維護日志節點所占用的內存空間迅速增大,另外,jffsx文件系統在掛載時需要掃描整個FLASH的內容,以找出所有的日志節點,建立文件結構,對於大容量的NAND閃存會耗費大量時間。
        B、yaffs:Yet Another Flash File System
            yaffs/yaffs2是專為嵌入式系統使用NAND型閃存而設計的一種日志型文件系統。與jffs2相比,它減少了一些功能(例如不支持數據壓縮),所以速度更快,掛載時間很短,對內存的占用較小。
            另外,它還是跨平台的文件系統,除了Linux和eCos,還支持WinCE, pSOS和ThreadX等。
            yaffs/yaffs2自帶NAND芯片的驅動,並且為嵌入式系統提供了直接訪問文件系統的API,用戶可以不使用Linux中的MTD與VFS,直接對文件系統操作。當然,yaffs也可與MTD驅動程序配合使用。
            yaffs與yaffs2的主要區別:yaffs僅支持小頁(512 Bytes) NAND閃存,yaffs2則可支持大頁(2KB) NAND閃存。同時,yaffs2在內存空間占用、垃圾回收速度、讀/寫速度等方面均有大幅提升。
        C、nfs網絡文件系統
            NFS是由Sun開發並發展起來的一項在不同機器、不同操作系統之間通過網絡共享文件的技術。
            在嵌入式Linux系統的開發調試階段,可以利用該技術在主機上建立基於NFS的根文件系統,掛載到嵌入式設備,可以很方便地修改根文件系統的內容。
        D、ubifs(UnsortedBlock Image File System,UBIFS)無排序區塊圖像文件系統
            UBIFS可以認為是JFFS2文件系統的下一代。最早在2006年由IBM與Nokia的工程師ThomasGleixner,ArtemBityutskiy所設計,專門為了解決MTD(MemoryTechnology Device)設備所遇到的瓶頸。由於NandFlash容量的暴漲,YAFFS等皆無法再去控制NandFlash的空間。UBIFS通過子系統UBI處理與MTDdevice之間的動作。
            UBIFS在設計與性能上均較YAFFS2、JFFS2更適合NAND FLASH。UBIFS支持write-back,其寫入的數據會被cache,直到有必要寫入時才寫到flash,大大地降低分散小區塊數量並提高I/O效率。UBIFSUBIFS文件系統目錄存儲在flash上,UBIFSmount時不需要scan整個flash的數據來重新創建文件目錄。支持on-the-flight壓縮文件數據,而且可選擇性壓縮部份文件。另外UBIFS使用日志(journal),可減少對flashindex的更新頻率。
        E、ext4文件系統
             ext4和yaffs2是日志類型的文件系統。日志文件系統就是一種具有故障恢復能力的文件系統,它利用日志來記錄尚未提交到文件系統的修改,以防止元數據破壞。
            一般來說,ext2或者ext4的文件系統不適用於nand flash,因為nand flash的讀寫特性,一般使用專為nand flash開發的文件系統,如yaffs2,jffs2,ubifs等。
————————————————
版權聲明:本文為CSDN博主「o倚樓聽風雨o」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/silent123go/article/details/52642841


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM