`
Michaelmatrix
  • 浏览: 222372 次
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

如何使用没有initrd的内核来启动U盘系统的几种方法

 
阅读更多

具体症状

目前,在Linux系统中,由于内核中U盘驱动usb-storage模块初始化比较慢,导致在U盘启动时,会出现U盘还没有启动完成,就开始挂载Linux系统分区的问题,因此导致在挂载系统时,出现找不到系统分区的情况,导致内核无法正常运行。

解决思路

针对这个问题,目前可以着手进行的方法有两个:

思路一:加快usb-stroage模块的初始化速度,使其能够在挂载文件系统前完成。

思路二:在进行文件系统挂载前等待一点时间,让usb-stroage模块能够正常的初始化完成,再进行挂载。

思路分析

思路一分析

加快usb-stroage模块的初始化速度,使其能够在挂载文件系统前完成。这个想法的优点在于可以从根本上解决启动速度慢的问题,但是根据对USB存储介质的初始化过程了解以后,发现由于U盘介质本身的访问和读写速度比较慢,导致在驱动层面上,要在很多地方不停的去等待,去探测。由于考虑到U盘介质不同,访问和读写速度也不一样的问题,所以在驱动中的好多地方都使用了等待一秒或者几毫秒后就去重新访问U盘,初始化U盘的方法,其实从内核代码层面上来看,已经没有什么可以值得优化的了,之所以初始化U盘比较慢,主要是慢在了U盘介质上。或许等USB 3.0规范发布以后,这种局面会有所好转。

目前,经过计时发现一个8GU盘的访问速度竟然达到了5秒钟的时间。可想而知U盘介质的访问和读写速度的确不太适合用作存储操作系统的介质。

思路二分析

等待usb-stroage模块初始化完成后,再进行挂载文件系统的操作。这种思路的启动速度虽然不如第一种思路的启动速度那样快,但是这种思路却能够切实的解决现有的问题。

初步想法是,在内核初始化文件系统代码前加上一段等待的代码,使其能够等待usb-stroage模块初始化后再进行启动。

内核启动代码深度分析

在内核源码中,具体的启动都是从各种架构下的汇编预言文件开始初始化的。在这里具体的内存分配,启动指令导入都规定好了。然而,查看这些汇编语言会发现,具体调用到内核中设备初始化和内存分配,cpu初始化以及分配情况的函数确是start_kernel。这个函数位于init目录,这就是内核初始化代码的开始。内核的启动过程都是从这里开始的。在这个目录下面,有一个叫做main的文件,在其中定义了几种内核参数加入时的处理函数。例如内核信息的打印模式,例如debug模式和quiet模式各有所不同,同事还指定了CPU最大数maxcpus,是否是多核处理器的参数nosmp参数加入时的各自不同的处理方式。

start_kernel函数中根据是否配置了CONFIG_BLK_DEV_INITRD进行了不同的处理,其处理过程大致是,根据输入的initrd的情况,指定initrd_start的情况。

start_kernel函数最后调用了rest_init。在这个函数中,单独分配了一个进程,给kernel_init函数。这才开始了真正的设备初始化,内存,CPU初始化,驱动加载,以及最终的如果没有initrd的情况下该如何处理的问题。

kernel_init函数首先是锁定到内核模式下运行。然后再对内存,CPU进行初始化。此时机器基本可以运行起来了。接着就是执行do_basic_setup函数来初始化机器中的所有设备。在这个过程中有一个函数叫做driver_init的函数。该函数将是内核中各个驱动模块初始化的入口点。其他函数将分别设置内存,CPU的值。这主要是根据内核启动时加入的参数决定的。

do_basic_setup函数完成之后,接下来就是选择启动脚本了。具体的代码如下:

在这里,程序调用prepare_namespace来开始挂载文件系统,启动init脚本等。经过对prepare_namespace的研究发现,在该函数中,有一个root_delay的过程,这个过程就是用来根据参数rootdelay的值,延迟root文件系统挂载的时间。也就是等待rootdelay参数规定的时间后,再开始挂载root文件系统分区,启动init脚本。而在这个时间段中,设备的初始化工作却没有间断。因为设备的初始化工作是在另外一个进程中进行的。所以我们可以在启动系统时,如果没有initrd的话,加入rootdelay参数来进行。此种做法可以作为方案一。

随着代码的深入,我们了解到,如果有initrd镜像,则根据initrd_load的结果,调整到out过程,开始执行切换主文件系统,并执行init脚本中的内容,最终启动整个操作系统。在没有initrd镜像的情况下,则继续向下执行设备初始化的工作。在这里将根据root_wait的值来看是否等待root文件系统的初始化过程。具体的代码如下:

在这里等待root文件系统初始化时,并不需要指定时间,而是每个100毫秒就去初始化一次ROOT_DEV 。如果初始化成功,则就不用再去等待。如果不成功,则需要继续等待,直到彻底初始化成功。

当然root_wait并不是刚开始就有的,也需要内核中加入参数,根据该参数来判断是否要等待。具体的参数就是rootwait。这个参数不需要赋值,只需要在启动时加入rootwait字样,内核就可以根据该字样来进行相关处理的。具体抓取该参数的函数如下:

rootwait可以做为我们解决内核启动的第二套方案实施。只需要加入该参数,让内核等待计算机上的所有设备都被初始化完成后,再去执行root文件系统的挂载工作。

其实在root文件系统初始化的过程,实际就是ROOT_DEV=name_to_dev_t(saved_root_name)的过程。在这个过程中,根据内核启动时指定的root=/dev/sda*来随着saved_root_name的存在,而产生/dev/root。具体的saved_root_nameroot=/dev/sda*挂钩的代码如下:

等有了/dev/root设备后,就可以进行mount_root函数了。在该函数中,就是切切实实的root文件系统的挂载过程了。而该函数的具体执行过程,实际就是随着config中指定的文件系统的不同格式,来进行不同的挂载形式。具体有NFSFD和块设备的挂载过程。由于U盘属于块设备,所以我们只需要研究块设备的挂载过程即可。块设备的具体挂载过程就是调用mount_block_root函数来进行。

经过我们对mount_block_root函数的分析和调试,发现在该函数中,当没有初始化出块设备时,挂载返回错误代号是-ENXIO。而在程序中,没有针对这个过程的处理方式。所以我们需要针对抓住-ENXIO代号的错误挂载后,进行一定的处理。在对遇到错误代码-ENXIO的处理过程,我们的基本思路是,使其等待一定的时间后,返回到retry段代码,再次开始挂载root分区的工作。如果说初始化U盘成功了,那么就不会再返回-ENXIO错误,而是返回0,挂载成功了。如果还是没有初始化U盘成功,则继续会返回-ENXIO错误代码,继续进行等待。知道初始化成功。具体的改进代码如下:

当然,这里面有很多是调试代码,还没有来得及进行优化。如果使用时,建议先优化后,在进行使用。这可以作为解决这个问题的第三种方案

解决方案

随着对内核启动代码的深度分析,可以得到三种具体的解决方案。详细分析如下:

方案一

在内核启动时,加入rootdelay=10的参数,来使内核在挂载文件系统前,先等待十秒钟,然后再开始挂载文件系统。这样做虽然能够解决系统启动时,无法挂载root文件系统的问题,但是要等待10秒中的时间。这与initrd的初始化时间相当,达不到加快系统启动速度的目标。另外,不同的U盘,存储介质不一样,初始化,读写的访问速度也不一样。这样一来,如果rootdelay给定的时间过短,会导致U盘还没有初始化完成,就挂载的情况,仍然达不到预期解决问题的目标,但是如果等待时间过长,会导致启动速度变慢。

优点:可以解决U盘文件系统的启动失败的问题;

缺点:如果输入值过小,则无法解决U盘文件系统启动失败的问题,如果输入值过大,会导致整个系统的启动速度变慢。

注意:一定要随着U盘介质的不同而选择合适的值来给rootdelay,否则会出现上述问题。

方案二

在内核启动时,加入参数rootwait参数,使内核在挂载文件系统前,等待root文件设备的初始化工作完成。此方案不仅可以解决U盘文件系统的启动失败的问题,而且也能很自动化的等待U盘的初始化,不需要浪费时间在等待U盘的启动上,同时也不会造成U盘还没有初始化完成就开始挂载的问题。

优点:1. 可以解决U盘文件系统的启动失败的问题;

2. u盘介质无关,不需要指定具体的初始化等待时间;

3. 很自动的调整,不会影响到系统的启动时间

缺点:

方案三

加入补丁来解决U盘文件系统的启动失败的问题。具体的补丁程序见上面对内核启动过程的深度分析。这种做法实际就是将rootwait的过程给代码化,程序化了而已。与rootwait没有什么区别。

分享到:
评论

相关推荐

    initrd 文件系统详解

    initrd 文件系统的工作机理是这样的:在 Linux 系统启动时,initrd 文件系统会被加载到内存中,然后 Linux 内核会从 initrd 文件系统中读取所需的文件和数据,以便正确地初始化和启动 Linux 系统。initrd 文件系统的...

    grub启动内核和initrd.img

    同时,我们也深入理解了`initrd.img`的作用及其制作方法,这对于进一步探索Linux系统的启动过程以及系统定制具有重要意义。最后,我们还了解了GRUB和Linux对于硬盘设备的不同表示方式,这对于正确配置GRUB及理解启动...

    Linux2.6 内核的 Initrd 机制解析

    ### Linux2.6 内核的 Initrd 机制解析 #### 深入理解Initrd技术 Initrd,全称Init RAM ...对于希望深入了解Linux启动过程的开发者和系统管理员来说,掌握Initrd的工作原理及其在2.6内核中的变化,无疑是至关重要的。

    linux2.6内核的Initrd机制解析

    Linux内核的Initrd机制是Linux操作系统启动过程中的一个重要组成部分,尤其在Linux 2.6内核中扮演了关键角色。Initrd,全称为“boot loader initialized RAM disk”,即由引导加载器初始化的内存磁盘。它是一个临时...

    Linux启动流程 initrd与initramfs的区别

    Linux启动流程可以分为几个主要的步骤,包括BIOS或UEFI的初始化、引导加载程序的加载、内核的加载和初始化、initrd或initramfs的加载以及根文件系统的挂载。其中,initrd和initramfs主要负责在系统完全启动之前,...

    用U盘做启动盘安装系统方法

    ### 使用U盘制作启动盘并安装操作系统的详细步骤 #### 一、BootICE工具的使用说明 **BootICE**是一款非常实用的小工具,主要用于管理硬盘的MBR(Master Boot Record,主引导记录)和分区的BOOT扇区。通过它,我们...

    linux内核启动地址修改

    总结来说,修改Linux内核启动地址是一个涉及到内存管理的重要过程,它可以帮助我们在多核系统或者需要特定硬件资源分配的场合中,更高效地使用有限的内存资源。通过上述步骤,可以灵活地调整内核与DSP在内存中的位置...

    vmlinuz.txt与initrd 用于windows中安装linux

    initrd(Initial RAM Disk)是一种临时的文件系统,它在内核启动早期被加载到内存中,用以执行特定的初始化任务,如加载驱动程序以访问真实的根文件系统。initrd可以包含特定于硬件的驱动程序,这些驱动程序可能在...

    基于Linux源代码及Busybox源代码制作精简可启动内核镜像

    **基于Busybox的根文件系统虚拟盘initrd.gz的制作**: Busybox提供了构建根文件系统的基本工具,你可以通过配置和编译Busybox,然后将其生成的可执行文件和其他必要文件打包成initrd.gz,这是一个初始化RAM磁盘,...

    Linux2.6内核启动流程.doc

    - 如果启用了initrd,内核会尝试挂载并使用它,直到找到永久的根文件系统为止。 8. **调度器和系统调用初始化**: - 初始化调度器,这是多任务操作的基础。 - 设置系统调用表,允许用户空间进程与内核交互。 9....

    制作用U盘启动的Linux系统.docx

    这个过程涉及到几个关键步骤,主要包括U盘的分区、格式化、安装文件系统、加载启动项、制作引导加载器(GRUB)以及安装必要的命令库。 1. **U盘处理** - **分区**:首先,使用`fdisk`工具删除U盘原有的分区(如果...

    initrd.img文件分析

    initrd.img 文件是 Linux 系统启动过程中的一个关键文件,它负责加载系统所需的驱动程序和模块,以便系统能够正确地启动和运行。initrd.img 文件的分析可以帮助我们更好地理解系统的启动过程,并且可以根据需要对 ...

    基于Linux源代码及Busybox源代码制作精简可启动内核镜像方法

    - **使用unetbootin**:打开unetbootin工具,选择相应的ISO镜像文件(包含内核镜像和根文件系统),指定U盘设备,点击“OK”开始制作可启动U盘。 #### 五、制作可启动的光盘镜像与磁盘镜像 1. **制作可启动光盘...

    initrd映像文档的作用和制作

    `initrd`是Linux系统启动过程中的关键组件,它提供了一种在内核加载后、挂载真实根文件系统之前的初始化环境。通过`mkinitrd`工具,我们可以根据内核版本创建定制的`initrd`映像,包含特定的驱动程序和初始化脚本,...

    在LINUX内核中添加系统调用

    最后,生成新的初始化ramdisk(`initrd`),并修改GRUB启动配置,确保系统启动时加载新的内核。 为了测试新添加的系统调用,可以编写一个用户空间的测试程序,如`test1.c`,并编译运行。通过`dmesg`命令查看系统日志...

    编译XEN4.0内核的几种方法

    编译XEN内核有几种方法,包括`make dist`,`makeworld`和`make install`。`make dist`是一种常用的编译方式,它会从远程源获取并编译所需的所有组件。如果你想要一个快速且简单的编译过程,可以尝试`makeworld`或`...

    initrd机制解析-我的笔记

    Linux2.6 内核支持两种格式的 initrd,一种是前面第 3 部分介绍的 Linux2.4 内核那种传统格式的文件系统镜像-image-initrd,它的制作方法同 Linux2.4 内核的 initrd 一样,其核心文件就是 /linuxrc。另外一种格式的...

    U盘启动制作工具和说明

    这种工具能够将操作系统的引导文件写入U盘,使得在没有操作系统或者系统出现问题时,U盘能作为一个临时的启动媒介来运行修复或安装程序。 1. **菜单配置文件(menu.lst)** `menu.lst`是Syslinux启动加载器的配置...

Global site tag (gtag.js) - Google Analytics