先簡單介紹一下ramdisk,Ramdisk是虛擬于RAM中的盤(Disk)。對于用戶來說,可以把RAM disk與通常的硬盤分區(如/dev/hda1)同等對待來使用,例如:
redice # mkfs.ext2 /dev/ram0mke2fs 1.38 (30-Jun-2005)Filesystem label=OS type: linuxBlock size=1024 (log=0)Fragment size=1024 (log=0)2048 inodes, 8192 blocks409 blocks (4.99%) reserved for the super userFirst data block=11 block group8192 blocks per group, 8192 fragments per group2048 inodes per groupWriting inode tables: doneWriting superblocks and filesystem accounting information: doneThis filesystem will be automatically checked every 24 mounts or180 days, whichever comes first. Use tune2fs -c or -i to override.redice # mount /dev/ram0 /mnt/rdredice # ls /mnt/rdlost+foundredice # mount/dev/hda2 on / type ext3PRoc on /proc type proc (rw)/dev/ram0 on /tmp/xxx type ext2 (rw) 當然,Ramdisk與硬盤分區有其不同的地方,例如RAM disk不適合作為長期保存文件的介質,掉電后Ramdisk的內容會隨內存內容的消失而消失。Ramdisk的其中一個優勢是它的讀寫速度高,可以被用作需要高速讀寫的文件。但在2.6版本后,Ramdisk的這一作用開始被tmpfs(Virtual memory file system support)取代。回到上面的例子,我們格式化了一個ramdisk(/dev/ram0)并且將其mount到/mnt/rd目錄下,那么這個Ramdisk有多大呢?先看一下:
redice # df -h /dev/ram2Filesystem 容量 已用 可用 已用% 掛載點/dev/ram0 7.8M 1.0K 7.4M 1% /mnt/rd
從上面的信息看出,ramdisk有大約7.8M的可用空間。我們再試一下另外的文件系統,重新格式化成minix分區并掛接試一下:
redice # umount /mnt/rdredice # mkfs.minix /dev/ram02752 inodes8192 blocksFirstdatazone=90 (90)Zonesize=1024Maxsize=268966912redice # mount /dev/ram0 /mnt/rdredice # df -h /dev/ram0Filesystem 容量 已用 可用 已用% 掛載點/dev/ram0 8.0M 1.0K 8.0M 1% /mnt/rd
現在看出來了,的確是8M(這同時說明,EXT2文件系統本身要占用一定的存儲空間,相比之下minix文件系統要少些),這個空間是在編譯核心時就確定下來了,在配置Ramdisk時,有一個叫
Default RAM disk size 的參數決定默認情況下Ramdisk的大小。可以通過核心命令行參數(ramdisk_size)來改變這個值,例如要設置Ramdisk的大小為16M,在grub中可以用:
# grub.conf -default=0timeout=10splashimage=(hd0,0)/grub/splash.XPm.gztitle Redice Linux root (hd0,0) kernel /vmlinuz ro root=LABEL=/ hdc=ide-scsi ramdisk_size=16384 initrd /initrd
這樣,Ramdisk的大小就變成16M了。這個參數是Ramdisk直接編譯到核心時才能使用的,假如Ramdisk編譯為模塊,則應該使用模塊參數來設置Ramdisk的大小:
redice # insmod rd rd_size=16384
編譯到核心時,可以通過下面的一些核心命令行參數來配置Ramdisk:
- ramdisk_size - ramdisk的大小(Kbytes);
- ramdisk - 與ramdisk_size的作用相同;
- ramdisk_blocksize - ramdisk的塊大小,默認情況為1024;
當以模塊的形式譯時,模塊支持以下幾個加載參數:
- rd_size - 同上面的ramdisk_size或ramdisk參數;
- rd_blocksize - 同上面的ramdisk_blocksize;
上面已經提到,Ramdisk需要先格式化然后理能使用。那么,假如核心希望使用ramdisk該如何做呢?于是initrd產生了,initrd全稱是
initial RAM disk ,它提供一種讓核心可以簡單使用Ramdisk的能力,簡單的說,這些能力包括:
- 格式化一個 Ramdisk;
- 加載文件系統內容到Ramdisk;
- 將Ramdisk作為根文件系統;
我們可以將initrd形像的比作Norton
Ghost備份的硬盤分區,而Linux啟動階段的Ramdisk相當于一個未格式化的硬盤分區,核心可以直接將initrd的內容釋放到一個未初始化的Ramdisk里,這個過程與Ghost恢復一個分區的過程十分相似。于是,相應的內容被加載到相應的Ramdisk中,同時,這個Ramdisk也被格式化成某種由initrd格式所表達的分區格式。initrd與Ghost備份的分區有許多相似之處,例如,它有一定的大小,包含分區上的文件系統格式等。initrd支持的格式包括:
- Ext2文件系統;
- Romfs文件系統;
- cramfs文件系統;
- minix文件系統;
假如核心選擇了Gz
ip支持(通常這是默認的,在init/do_mounts_rd.c中定義的BUILD_CRAMDISK宏)還可以使用Gzip壓縮的initrd。相關的代碼可以在核心
源碼 drivers/block/rd.c:identify_ramdisk_image 中找到。
制作initrd
制作initrd傳統的作法是通過軟盤(顯然過時了,不介紹了)、ramdisk或loop設備(/dev/loop)。通過ramdisk來制作的方法比較簡單(以ext2文件系統為例):
redice # mkfs.ext2 /dev/ram0redice # mount /dev/ram0 /mnt/rdredice # cp _what_you_like_ /mnt/rd # 把需要的文件復制過去redice # dd if=/dev/ram0 of=/tmp/initrdredice # gzip -9 /tmp/initrd
這個過程也最能夠解釋initrd的本質,對于Linux來說,Ramdisk的一個塊設備,而initrd是這個塊設備上所有內容的“克隆”(由命令dd來完成)而生成的文件。核心中加載initrd相關的代碼則用于完成將相反的過程,即將這一個文件恢復到Ramdisk中去。通過loop設備來制作initrd的過程:
redice # dd if=/dev/zero of=/tmp/initrd bs=1024 count=4096 # 制作一個4M的空白文件redice # losetup /dev/loop0 /tmp/initrd # 映射到loop設備上;redice # mkfs.ext2 /dev/loop0 # 創建文件系統;redice # mount /dev/loop0 /mnt/rdredice # cp _what_you_like_ /mnt/rd # 復制需要的文件;redice # umount /mnt/rdredice # losetup -d /dev/loop0redice # gzip -9 /tmp/initrd
不過,現在已經有了一些更好的工具來完成這些工作,包括genromfs(UClinux里常用的工具),genext2fs,mkcramfs等。這些工具提供了一些方便開發的新特性,例如,不需要上面煩索的過程,只要將文件復制到某個目錄中,將其作為根目錄,即可生成initrd;另一個重要的改進是,這些工具都可以以普通用戶的身份來生成initrd。未完,待續…(補充有關如何加載ARM中如何使用initrd作為根文件系統等)