打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
dev目录的始末-waityoualife

主要内容

通过学习dev目录的创建来了解内核启动过程中的一些详细信息。Dev目录是存放设备节点的目录,通过我们分析dev目录可以进一步了解内核。

我们主要从两点讲述

1:dev目录的创建过程

2:设备节点的创建过程

历史

主要介绍dev目录的发展史。

静态dev目录

最初的dev目录是静态,所有的设备节点是手动、事先创建的。这样随着设备发展,这个目录会越来越大。我们不知道系统需要哪里设备,所以必须要将可能的设备事先全部创建。

Devfs

Devfs和procfs、sysfs文件系统一样,都是内核文件系统。因为有其自身缺点,所以目前不再说使用。

Tmpfs和udev

目前的dev是个tmpfs文件系统,它是个用户文件系统,与内核没有一点关系。在设备插拔时,由udev工具根据事先的规则动态添加和删除设备节点,即dev目录下的文件。

Dev创建过程

Dev的创建过程比较复杂,我们一步步讲解。

第一步

initrd是个文件系统,是通过mkinitrd工具创建的,是内核起始过载的第一个根文件系统。

通过gunzip、cpio打开这个文件:

bin  dev  etc  init  lib  proc  sbin  sys  sysroot

打开dev目录:

console  null  ram   ram1  systty  tty0  tty10  tty12  tty3  tty5  tty7  tty9   ttyS1  zero mapper   ptmx  ram0  rtc   tty     tty1  tty11  tty2   tty4  tty6  tty8  ttyS0  ttyS2

Initrd目录下面的dev目录是静态创建了,并包含了许多常见的设备节点,这些设备节点在内核启动时需要的。这是dev目录的第一版。在执行到第二步之前,系统使用该目录下的设备节点。

第二步

在initrd中下面有个脚本文件init:

#!/bin/nash

 

mount -t proc /proc /proc

setquiet

echo Mounting proc filesystem

echo Mounting sysfs filesystem

mount -t sysfs /sys /sys

echo Creating /dev

mount -o mode=0755 -t tmpfs /dev /dev

mkdir /dev/pts

mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts

mkdir /dev/shm

mkdir /dev/mapper

echo Creating initial device nodes

mknod /dev/null c 1 3

mknod /dev/zero c 1 5

mknod /dev/systty c 4 0

mknod /dev/tty c 5 0

mknod /dev/console c 5 1

mknod /dev/ptmx c 5 2

mknod /dev/rtc c 10 135

mknod /dev/tty0 c 4 0

mknod /dev/tty1 c 4 1

mknod /dev/tty2 c 4 2

mknod /dev/tty3 c 4 3

mknod /dev/tty4 c 4 4

mknod /dev/tty5 c 4 5

mknod /dev/tty6 c 4 6

mknod /dev/tty7 c 4 7

mknod /dev/tty8 c 4 8

mknod /dev/tty9 c 4 9

mknod /dev/tty10 c 4 10

mknod /dev/tty11 c 4 11

mknod /dev/tty12 c 4 12

mknod /dev/ttyS0 c 4 64

mknod /dev/ttyS1 c 4 65

mknod /dev/ttyS2 c 4 66

mknod /dev/ttyS3 c 4 67

echo Setting up hotplug.

hotplug

echo Creating block device nodes.

mkblkdevs

echo "Loading ehci-hcd.ko module"

insmod /lib/ehci-hcd.ko 

echo "Loading ohci-hcd.ko module"

insmod /lib/ohci-hcd.ko 

echo "Loading uhci-hcd.ko module"

insmod /lib/uhci-hcd.ko 

mount -t usbfs /proc/bus/usb /proc/bus/usb

echo "Loading jbd.ko module"

insmod /lib/jbd.ko 

echo "Loading ext3.ko module"

insmod /lib/ext3.ko 

echo "Loading scsi_mod.ko module"

insmod /lib/scsi_mod.ko 

echo "Loading sd_mod.ko module"

insmod /lib/sd_mod.ko 

echo "Loading libata.ko module"

insmod /lib/libata.ko 

echo "Loading sata_sil.ko module"

insmod /lib/sata_sil.ko 

echo "Loading ata_piix.ko module"

insmod /lib/ata_piix.ko 

echo "Loading ahci.ko module"

insmod /lib/ahci.ko 

echo "Loading usb-storage.ko module"

insmod /lib/usb-storage.ko 

echo Waiting for driver initialization.

stabilized /proc/bus/usb/devices

echo "Loading dm-mem-cache.ko module"

insmod /lib/dm-mem-cache.ko 

echo "Loading dm-mod.ko module"

insmod /lib/dm-mod.ko 

echo "Loading dm-log.ko module"

insmod /lib/dm-log.ko 

echo "Loading dm-region_hash.ko module"

insmod /lib/dm-region_hash.ko 

echo "Loading dm-message.ko module"

insmod /lib/dm-message.ko 

echo "Loading dm-raid45.ko module"

insmod /lib/dm-raid45.ko 

echo Waiting for driver initialization.

stabilized --hash --interval 1000 /proc/scsi/scsi

mkblkdevs

echo Scanning and configuring dmraid supported devices

echo Creating root device.

mkrootdev -t ext3 -o defaults,ro hda2

echo Mounting root filesystem.

mount /sysroot

echo Setting up other filesystems.

setuproot

echo Switching to new root and running init.

switchroot

该文件是用nash执行的,nash的源码在mkinitrd源码包中。

mount -o mode=0755 -t tmpfs /dev /dev

在执行init脚本时,会重新挂载dev,这时的dev就是个tmpfs文件系统了。挂载后dev目录下是空的,所以后面就会创建许多基本设备文件,这些设备节点和第一步的dev目录下的设备节点基本相同。

同时在init脚本中,会加载各种块设备文件和文件系统驱动。这时系统就会有许多块设备,但是系统是如果在dev下面创建设备节点的?

系统是通过nash的命令:mkblkdevs来创建设备节点。该命令是根据proc文件系统下的partitions文件创建设备节点的。

但是我们知道当前的根文件系统并不是系统启动后的真正根文件系统,那么等我们的根文件系统启动后,我们发现dev目录仍然是tmpfs。那么就会有两个问题:

1:我们根文件系统下dev目录是何时挂载的?

2:在内核启动过程中发现的块设备节点,又是如何在dev目录显示。

第三步

在init脚本中有个setuproot命令,我们分析nash中的setuproot发现:

if (mount("/dev", "./dev", NULL, MS_BIND, NULL) < 0)

        eprintf("setuproot: moving /dev failed: %m\n");

这句话是至关重要的。它将原来的dev挂载到系统启动的根文件系统的dev目录下面。但是我们知道/dev是个目录,是不能挂载的。那么系统是如果成功的呢?

注意到参数MS_BIND。能够挂载成功,是靠该参数。

--bind Remount  a  subtree  somewhere else (so that its contents are available in both places).

可以简单解释下:

我们知道块设备可以挂载到多个目录,其内容不变。但是由于在第二步挂载的tmpfs /dev是tmpfs,所以我们不能象其他文件系统一样,再次挂载到其他目录下面。如果我们再次mount -t tmpfs /dev/ ./dev那么我们原来的设备节点都不会存在,对于那些在init中静态创建的设备节点是可以,但是对于那些块设备节点就不能再次创建,这样这些设备都会丢失。

为了解决这个问题,我们采用参数--bind。

下面看一个例子:

Mount -t tmpfs A B

Mount --bind B  C 

这样相当于块设备的多次挂载。这时C目录和B目录是相同。这也正是我们需要的。

此时挂载成功后,tmpfs /dev就会挂载在/dev(init文件系统)、./dev(真正的根文件系统),同时保留了原理tmpfs /dev目录下的设备节点。

第四步

在switchroot命令中:

const char *umounts[] = { "/dev", "/proc", "/sys", NULL };

for (; umounts[i] != NULL; i++) {

        qprintf("unmounting old %s\n", umounts[i]);

        if (umount2(umounts[i], MNT_DETACH) < 0) {

            eprintf("ERROR unmounting old %s: %m\n",umounts[i]);

            eprintf("forcing unmount of %s\n", umounts[i]);

            umount2(umounts[i], MNT_FORCE);

        }

   }

系统会将在init中的/dev卸载,所以在系统启动中会打印:

Unmounting old /dev

Unmounting old /proc

Unmounting old /sys

但是在执行这一步时,我们已经在第三步将/dev重新挂载到./dev下面,所以不会导致设备节点丢失。

同时init(第一个用户进程)启动,系统进入用户态。也可以这么说在进入init时,在启动时发现的块设备节点都已经创建了。

第五步

Init(第一个用户进程)执行脚本rc.sysinit:

/sbin/start_udev

启动udev,自此udev这个用户空间程序,负责位dev目录下面创建或者删除设备节点。

Start_udev是个脚本文件,其启动udevd。

Dev目录

Dev目录下面有许多有意思的文件,我们简单分析下。

Disk

该目录下面是关于系统中的块设备的符号链接。按照不同的标准分类。

by-id 

符号链接,通过分析这个可以得到块设备的一些信息。

lrwxrwxrwx 1 root root  9 Jul 21 10:18 ata-InnoDisk_Corp._-_iCF4000_4GB_20080814AA2A70000050 -> ../../hda

lrwxrwxrwx 1 root root 10 Jul 21 10:18 ata-InnoDisk_Corp._-_iCF4000_4GB_20080814AA2A70000050-part1 -> ../../hda1

lrwxrwxrwx 1 root root 10 Jul 21 10:18 ata-InnoDisk_Corp._-_iCF4000_4GB_20080814AA2A70000050-part2 -> ../../hda2

lrwxrwxrwx 1 root root  9 Jul 21 10:18 scsi-SATA_ST3320310CS_5TX03LHM -> ../../sdd

lrwxrwxrwx 1 root root  9 Jul 21 10:18 scsi-SATA_ST3320310CS_5TX03LQK -> ../../sdc

lrwxrwxrwx 1 root root  9 Jul 21 10:18 scsi-SATA_ST3320310CS_5TX05RDH -> ../../sdb

lrwxrwxrwx 1 root root  9 Jul 21 10:18 scsi-SATA_ST3320310CS_5TX070WQ -> ../../sda

lrwxrwxrwx 1 root root 10 Jul 21 10:18 scsi-SATA_ST3320310CS_5TX070WQ-part1 -> ../../sda1

lrwxrwxrwx 1 root root  9 Jul 21 10:18 scsi-SATA_ST3320620AS_6QF4SSS2 -> ../../sdg

lrwxrwxrwx 1 root root  9 Jul 21 10:18 scsi-SATA_ST3320620SV_5QF7F5F0 -> ../../sde

lrwxrwxrwx 1 root root  9 Jul 21 10:18 scsi-SATA_ST3320620SV_9QFBE47N -> ../../sdf

lrwxrwxrwx 1 root root  9 Jul 21 10:18 scsi-SATA_ST3320620SV_9QFBE7FS -> ../../sdh

lrwxrwxrwx 1 root root 10 Jul 21 10:18 scsi-SATA_ST3320620SV_9QFBE7FS-part1 -> ../../sdh1

by-label 

使用label的块设备。

lrwxrwxrwx 1 root root 10 Jul 21 10:18 boot -> ../../hda1

by-path 

块设备的父设备,比较有用。

lrwxrwxrwx 1 root root  9 Jul 21 10:18 pci-0000:00:1f.1-ide-0:0 -> ../../hda

lrwxrwxrwx 1 root root 10 Jul 21 10:18 pci-0000:00:1f.1-ide-0:0-part1 -> ../../hda1

lrwxrwxrwx 1 root root 10 Jul 21 10:18 pci-0000:00:1f.1-ide-0:0-part2 -> ../../hda2

lrwxrwxrwx 1 root root  9 Jul 21 10:18 pci-0000:01:01.0-scsi-0:0:0:0 -> ../../sda

lrwxrwxrwx 1 root root 10 Jul 21 10:18 pci-0000:01:01.0-scsi-0:0:0:0-part1 -> ../../sda1

lrwxrwxrwx 1 root root  9 Jul 21 10:18 pci-0000:01:01.0-scsi-1:0:0:0 -> ../../sdb

lrwxrwxrwx 1 root root  9 Jul 21 10:18 pci-0000:01:01.0-scsi-2:0:0:0 -> ../../sdc

lrwxrwxrwx 1 root root  9 Jul 21 10:18 pci-0000:01:01.0-scsi-3:0:0:0 -> ../../sdd

lrwxrwxrwx 1 root root  9 Jul 21 10:18 pci-0000:01:02.0-scsi-0:0:0:0 -> ../../sde

lrwxrwxrwx 1 root root  9 Jul 21 10:18 pci-0000:01:02.0-scsi-1:0:0:0 -> ../../sdf

lrwxrwxrwx 1 root root  9 Jul 21 10:18 pci-0000:01:02.0-scsi-2:0:0:0 -> ../../sdg

lrwxrwxrwx 1 root root  9 Jul 21 10:18 pci-0000:01:02.0-scsi-3:0:0:0 -> ../../sdh

lrwxrwxrwx 1 root root 10 Jul 21 10:18 pci-0000:01:02.0-scsi-3:0:0:0-part1 -> ../../sdh1

by-uuid

如果块设备或者分区,有文件系统,那么就会出现在该目录下面。

lrwxrwxrwx 1 root root 10 Jul 21 10:18 46c68b18-4954-4738-9738-a91bbe18df0e -> ../../hda1

lrwxrwxrwx 1 root root 10 Jul 21 10:18 8750fc53-2c73-d7b3-e941-f85db95f5be6 -> ../../sdh1

lrwxrwxrwx 1 root root 10 Jul 21 10:18 999edb78-d3f6-42cf-87ed-616099860da8 -> ../../hda2

lrwxrwxrwx 1 root root 10 Jul 21 10:18 a91da518-770d-4ae0-81eb-26583e2de0cd -> ../../sda1

lrwxrwxrwx 1 root root  9 Jul 21 10:18 d5254e53-34e2-ee36-d5c9-839a431774e6 -> ../../sdc

Mapper

使用LVM创建的块设备。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
[实践]busybox1.16.1建立文件系统
文件系统:Linux下磁盘设备文件(sda,sdb,sdc….)变化的问题
Linux磁盘及分区之wwid和uuid
VMware虚拟机(Linux)如何找出系统中磁盘设备对应的硬盘
如何在 Linux 上扫描/检测新的 LUN 和 SCSI 磁盘 | Linux 中国
linux
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服