用户名: 密码: 忘记密码? 注册

ramdisk/ramfs/tmpfs/initrd/initramfs/rootfs/cpio

作者:  时间: 2010-09-20
  一 RAMDISK VS INITRD

  先简单介绍一下ramdisk,Ramdisk是虚拟于RAM中的盘(Disk)。对于用户来说,可以把RAM disk与通常的硬盘分区(如/dev/hda1)同等对待来使用

  # mkfs.ext2 /dev/ram0

  # mount /dev/ram0

  # mkdir /mnt/rd

  # mount /dev/ram0 /mnt/rd

  # ls /mnt/rd

  lost+found

  # df -h /dev/ram0

  编译到核心时,可以通过下面的一些核心命令行参数来配置Ramdisk:

  ramdisk_size - ramdisk的大小(Kbytes);

  initrd概述

  上面已经提到,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文件系统;

  1)传统方法制作initrd

  # mkfs.ext2 /dev/ram0

  # mount /dev/ram0 /mnt/rd

  # cp _what_you_like_ /mnt/rd

  # dd if=/dev/ram0 of=/tmp/initrd

  # gzip -9 /tmp/initrd

  (由此可见,initrd文件就是ext2格式的盘,当它释放到没有格式的ramdisk的时候,ramdish自然被格式化成ext2格式的盘了,这个格式是由initrd决定的。)

  这个过程也最能够解释initrd的本质,对于Linux来说,Ramdisk的一个块设备,而initrd是这个块设备上所有内容的“克隆”(由命令dd来完成)而生成的文件。核心中加载initrd相关的代码则用于完

  成将相反的过程,即将这一个文件恢复到Ramdisk中去。

  2)通过loop设备来制作initrd的过程:

  # dd if=/dev/zero of=/tmp/initrd bs=1024 count=4096 # 制作一个4M的空白文件

  # losetup /dev/loop0 /tmp/initrd # 映射到loop设备上;

  # mkfs.ext2 /dev/loop0 # 创建文件系统;

  # mount /dev/loop0 /mnt/rd

  # cp _what_you_like_ /mnt/rd # 复制需要的文件;

  # umount /mnt/rd

  # losetup -d /dev/loop0

  # gzip -9 /tmp/initrd

  3)另外使用loop设备制作initrd的过程

  # dd if=/dev/zero of=/tmp/initrd bs=1024 count=4096 # 制作一个4M的空白文件

  # mkfs.ext2 /tmp/initrd

  # mount /tmp/initrd /mnt/rd -t ext2 -o loop=/dev/loop0

  # cp _what_you_like_ /mnt/rd # 复制需要的文件;

  # umount /mnt/rd

  # gzip -9 /tmp/initrd

  (由此可见,loop就是一个设备文件,initrd必须和设备文件绑定或映射或等同,才进行近一步的操作。mount可分解成losetup /dev/loop0 /tmp/initrd and mount /dev/loop0 /mnt/rd)

  使用ram disk初始化(initrd)

  initrd提供了在boot loader下加载ram disk的方法。该ram disk可以被作为根文件系统挂载进来,里面的程序也可以运行。然后,新的根文件系统可以从其他设备挂载。之前的根(来自initrd)可以被

  转移到一个目录然后被卸载。

  initrd主要设计用来使系统启动于两个条件,一个是内核来自于非常小的驱动器,一个是额外的模块需要从initrd中加载。

  当使用initrd,典型的系统启动顺序如下:

  1. boot loader加载内核并初始化ram disk

  2. 内核把initrd转化成正常的ram disk 并释放initrd使用的内存

  3. initrd作为root被挂载,赋予读写权限。

  4. /linuxrc被执行(这可以是任何可执行文件,如脚本,运行在uid 0,可以做任何初始化)。

  5. linuxrc挂载真正的根文件系统

  6. linuxrc使用pivot_root系统调用把根文件系统放在根目录。

  7. 正常的启动序列(/sbin/init)在根文件系统上执行。

  8. initrd文件系统被移去。

  二 RAMFS VS TMPFS vs ramdisk vs initramfs

  1.ramdisk是由块设备来实现的,必须格式化成某种文件格式才能使用,需要设备文件,例如ram0等,initrd就是initial ramdisk;编译内核时须将block device中的Ramdisk支持选上,它下面还有两个

  选项,一个是设定Ramdisk的大小,默认是4096k;另一个是initrd的支持。其不足之处是大小固定,之后不能改变。

  2.ramfs就是内存文件系统,不需要格式化,不需要设备文件,可以动态增长;

  3.tmpfs是虚拟内存文件系统,它不同于传统的用块设备形式来实现的ramdisk,也不同于针对物理内存的Ramfs,Tmpfs可以使用物理内存,也可以使用交换分区。在Linux内核中,虚拟内存资源由物理内

  存(RAM)和交换分区组成,这些资源是由内核中的虚拟内存子系统来负责分配和管理。 Tmpfs就是和虚拟内存子系统来"打交道"的,它向虚拟内存子系统请求页来存储文件,它同Linux的其它请求页的

部分一样,不知道分配给自己的页是在内存中还是在交换分区中。Tmpfs同Ramfs一样,其大小也不是固定的,而是随着所需要的空间而动态的增减。使用tmpfs,首先你编译内核时得选择"虚拟内存文件

  系统支持(Virtual memory filesystem support)" ,然后就可以加载tmpfs文件系统了。

  4.rootfs是ramfs的特殊实例, 在2.6的内核中必然存在。rootfs不能被卸载(与其添加特殊代码用来维护空的链表,不如把rootfs节点始终加入,因此便于kernel维护:简单、精炼。rootfs是ramfs的一

  个空实例,占用空间极小)。大部分其他的文件系统安装于rootfs之上。

  5.initramfs:2.6的Linux内核包含有gzip压缩的cpio格式的文档,可以在内核引导的时候解压缩为rootfs

   6.补充:通常情况下,Linux的所有文件在内存中都有缓存。需要读取的数据页从支撑存储设备(block device)中读取后,缓存于内存。在支撑存储设备中的数据页执行marked as clean操作。当虚拟文件系统需要支撑存储设备中的数据页内存时,可以释放。基于同样的机制,支撑存储设备的写入操作(写入文件然后写回支撑存储设 备,marked as clean)后,也可以释放占用的数据页内存。对于文件目录占用的缓存(dentry: directory entry),也存在同样的机制。但是,ramfs中不需要支撑存储设备(没有支撑缓存,但是有缓存)。也就是说,写入ramfs的文件可以正常的分配 page cache and dentry cache,但是不能写入支撑存储设备。这些page cache and dentry cache不能被VM释放、回收。由于ramfs可以基于现有的Linux的文件系统结构,用于实现ramfs的代码很小。一般而言,支撑存储设备的缓存 被安装为一个文件系统。所以,ramfs不能通过menuconfig选择,是必然进入内核的。在 ramfs的下面可以一直写入数据,直到写满内存为止。由于VM(Vitual Memory)认为文件应该被写回支撑存储设备,而不是交换空间(swap space),所以VM不能释放ramfs分配的内存。从而,只有root用户(or trusted user)才能进行ramfs写操作。

  例1

  # mkdir -p /RAM1

  # mount -t ramfs none /RAM1

  例2

  # mkdir -p /RAM1

  # mount -t ramfs none /RAM1 -o maxsize=10000

  例3

  # mkdir -p /mnt/tmpfs

  # mount tmpfs /mnt/tmpfs -t tmpfs

  例如4

  # mount tmpfs /mnt/tmpfs -t tmpfs -o size=32m

  三 initrd vs initramfs

  1. initrd是一个单独的文件;initramfs和Linux内核链接在一起(/usr目录下的程序负责生成initramfs文档)。

  2. initrd是一个压缩的文件系统映像(可以是ext2等,需要内核的驱动);initramfs是类似tar的cpio压缩文档。内核中的cpio解压缩代码很小,而且init数据在boot后可以丢弃。

  3. initrd运行的程序(initd,不是init)进行部分setup后返回内核;initramfs执行的init程序不返回内核(如果/init需要向内核传递控制权,可以再次安装在/目录下一个新的root设备并且启动一个新

  的init程序)。

   4. 切换到另一个root设备时,initrd执行pivot_root后,卸载ramdisk;initramfs是rootfs,既不能 pivot_root,也不能卸载。initramfs会删掉rootfs的所有内容(find -xdev / -exec rm '{}' ';')

  ,再次安装root到rootfs(cd /newmount; mount --move . /; chroot .),把stdin/sdout/stderr挂在新的/dev/console上,重新执行init。由于这是一个相当困难的实现过程(包括在使用一个 命令之前

  把它删除),所以klibc工具包引入一个帮助程序/utils/run_init.c来执行上述过程。其他大部分工具包(包括busybox) 把这个命令称为"switch_root"。

  问题:

  在嵌入式中,rootfs即initramfs就是最终的根文件文件系统,是不是说这个根也是ramfs文件系统呢,没有和设备绑定的?命令行用到ram0,但ram0不是和ramdisk相关的嘛,如下

  # cat cmdline

  console=ttyS1,57600n8 root=/dev/ram0

  # mount

  rootfs on / type rootfs (rw)

  proc on /proc type proc (rw)

  none on /var type ramfs (rw)

  none on /etc type ramfs (rw)

  none on /tmp type ramfs (rw)

  none on /media type ramfs (rw)

  none on /sys type sysfs (rw)

  none on /dev/pts type devpts (rw)

  none on /proc/bus/usb type usbfs (rw)

  mdev on /dev type ramfs (rw)

  devpts on /dev/pts type devpts (rw)