|  | 
 
| 今天无意间看到一篇使系统服务并行运行加快系统启动速度的文章,于是 尝试了下,感觉办法很不错,同时让我对lfs的系统引导脚本有了更深的理解
 总觉得系统启动太慢的兄弟们不妨研究研究尝试下。
 原文在:
 http://www-900.ibm.com/developerWorks/cn/linux/l-boot/index.shtml
 03年11月的了,不知道有没有人已经在sir发过,刚才搜索下好象没找到。
 因为要修改系统启动的脚本,很可能让系统启动不正常,所以最好有双linux系统,即使修改错误了,还可以从另一个系统引导修复。
 如果很不幸,没有的话,可以先学下这招,紧急救护系统也有用
 grub菜单中选择linux,按e,e,进入编辑模式,kernel......那一行最后加上
 init=/bin/bash,这样引导系统可以得到一个bash shell
 这样进入的系统会是read-only的,首先先使用fsck检查系统
 fsck -a /dev/hdaX 处理根分区
 fsck -R -A -a 处理其他分区
 如果系统在上次重启,是正常重启的,文件系统是正常卸载的,可以不用fsck检查直接把系统挂载成read-write的
 mount / -o remount,rw
 mount /proc
 swap on -a 打开所有的交换分区
 在修复好系统后将系统重新挂载成ro的,就可以安全重启了。
 mount / -o remount,ro
 下面简单的说一下linux系统的启动过程。
 如果你想更了解系统的启动,这有篇文章非常好。
 http://www.faqs.org/docs/Linux-HOWT...ompt-HOWTO.html
 当grub加载内核后,/sbin/init首先从/etc/inittab取得运行级别
 id:3:initdefault: 这里启动级别是3--文本模式
 si::sysinit:/etc/rc.d/init.d/rc sysinit
 这一行代表在任何运行级别都去执行/etc/rc.d/init.d/rc
 sysinit 是传入的参数,并且这是init执行的第一个脚本,做系统的最基本的初始化,比如挂载proc系统拉,检查根分区拉,开启swap拉。等等
 但是在不同的发行版这个文件可能不同比如在Mandrakelinux中是:si::sysinit:/etc/rc.d/rc.sysinit
 init执行的则是/etc/rc.d/rc.sysinit
 经过了系统的初始化后,init开始读取run-level中的脚本,这些脚本位于
 /etc/rc.d/rcX.d目录下。X是当前的运行级别.这里是系统启动的服务,比如network,alsa,httpd....等
 l3:3:wait:/etc/rc.d/rc 3
 :3:表示这是在运行级别3中执行的脚本,wait表示init会等待这些脚本都执行
 完再继续运行,不知道如果改为once会怎么样,还没有实验....
 另外有的发行版会在执行rcX.d之后去执行/etc/rc.d/rc.local
 最后就看到可爱的login拉
 在/etc/rc.d/rcX.d中的脚本都是以SXX+服务名或者KXX+服务名组成的,并且都是到/etc/rc.d/init.d中相应脚本的符号链接,有的发行版是/etc/init.d
 其中XX是0-9的数字,数字越小,则启动的时间越早。
 以S开头的表示系统启动时传递start参数的服务,就是开启拉。K开头的就是
 传递stop参数拉。kill bill...
 /etc/rc.d/rc3.d:
 S10sysklogd@ S20network@ S25random@ S30httpd S40alsa@ S85numlock@
 可以看出,我的系统进入rc3.d时首先启动的服务是sysklogd,最后是numlock
 很明显,httpd服务必须要在network之后运行,不然没有网络哪来的web服务?想知道系统是怎么识别这些数字作为顺序的吧,俺也是今天才知道的。。
 原来是用ls -v 列出它们,挨个放血
 逐一的去执行它们,这样就会使系统启动的速度很慢,服务越多越明显
 现在希望做的就是,让那些相互之间没有依赖关系的服务可以同时开启,而不是逐一的执行,这样系统启动的速度就会加快很多了。
 而相互有依赖关系的服务,告诉make这些服务的依赖关系,然后让make去解决
 再使用make -j 参数使服务可以并行启动。
 在makefile中写入服务之间的相依赖关系
 httpd : network
 表示httpd依赖network,这样在network启动完毕,则可以启动httpd
 而其他不相依赖的服务可以同时进行,这样系统启动的速度就快多拉
 原理就是这样,下面是我的实际做法:
 首先是make 的配置文件:/etc/rc.d/runlevel.mk
 
 ########################################################################
 # Description : Gnu Makefile to control the services in the specified
 # runlevel. It will run the required services, and log
 # the output of the services to the file
 # /var/log/initd.start (for service startup) and
 # /var/log/initd.stop (for service shutdown).
 #
 # This controlling program is designed to be invoked by
 # the "/etc/rc.d/rc" script.
 #
 # Author : [email protected]
 #
 # Notes :
 #
 # - Run as,
 #
 # make [-n] -j -f runlevel.mk \
 # RUNLEVEL={0|1|2|3|4|5|6} \
 # JOB={start|stop|restart|status}
 #
 # - $(JOB) is not validated - that is left to the service program.
 # - $(RUNLEVEL) is not validated - that is left to the calling program
 # (usually /etc/rc.d/rc).
 # - It wouldn't take too much effort to auto-generate this Makefile.
 #
 ########################################################################
 
 # passed as a parameter
 RUNLEVEL =
 
 # passed as a parameter (start, stop, status, etc)
 JOB =
 
 # set to a value to enable debug output
 DEBUG =
 
 ########################################################################
 # START CONFIGURATION
 
 # system commands used by this facility
 CAT = /bin/cat
 RM = /bin/rm
 ECHO = /bin/echo
 DATE = /bin/date
 
 # Directory containing scripts/programs to run.
 INITD_DIR := /etc/rc.d/init.d #这里要修改成自己系统的所有服务脚本存放目录,有些发行版是/etc/init.d 这个目录必须正确
 
 # Directory into which a lock file is created when a service starts.
 # (Note that the lock file is created by the service).
 SUBSYS_FILE_DIR := /var/lock/subsys #这个目录自己创建
 
 # Used to create temporary files, before collating them all into
 # $(FINAL_OUTPUT_FILE).
 TMP_DIR := /tmp
 
 TMPFILE_PREFIX := .runlevel
 TMP_FILE = $(TMP_DIR)/$(TMPFILE_PREFIX).$(JOB).$@
 
 # File that contains all output of programs/scripts run.
 FINAL_OUTPUT_FILE = /var/log/initd.$(JOB)
 
 # List of *all* services.
 #
 # (Important Note: if you don't include a service in this list,
 # it won't get run!)
 #这里写上所有的需要启动的服务,这些服务的名字必须要与/etc/rc.d/init.d
 #中的名字一致的。
 ALL = \
 sysklogd \
 network \
 httpd \
 random \
 alsa \
 numlock \
 
 # END CONFIGURATION
 ########################################################################
 
 # Check command-line parameters
 ifndef RUNLEVEL
 $(error must specify RUNLEVEL, so I know what to run)
 endif
 
 ifndef JOB
 $(error must specify JOB, so I know what to do)
 endif
 
 default: $(ALL) create_final_output_file
 ifneq ($(DEBUG),)
 @$(ECHO) "RUNLEVEL=$(RUNLEVEL)"
 @$(ECHO) "JOB=$(JOB)"
 @$(ECHO) "FINAL_OUTPUT_FILE=$(FINAL_OUTPUT_FILE)"
 @$(ECHO) "TMP_FILE=$(TMP_FILE)"
 @$(ECHO) "ALL=|$(ALL)|"
 #@$(ECHO)
 #@$(ECHO) "ALL (less local)=|$(filter-out local,$(ALL))|"
 #@$(ECHO)
 #@$(ECHO) "ALL (less kudzu)=|$(filter-out kudzu,$(ALL))|"
 #@$(ECHO)
 endif
 
 ##############################################################
 # Generic rule to control a service.
 #
 # Note that we capture all output to a file.
 
 $(ALL) : $(SUBSYS_FILE_DIR)/$@
 @$(ECHO) "Begin \"$(JOB) $@\" at `$(DATE)`" > $(TMP_FILE)
 @$(INITD_DIR)/$@ $(JOB) >> $(TMP_FILE) 2>&1
 @$(ECHO) "End \"$(JOB) $@\" at `$(DATE)`" >> $(TMP_FILE)
 
 ##############################################################
 # List of services that have dependencies.
 #
 # (Note: It is not necessary to list services that have no
 # dependencies).
 
 # Include the relevant dependencies. If you intend to use this facility,
 # you must provide 2 makefiles / runlevel, one for starting the services
 # in the runlevel, and one for stopping the services in the runlevel.
 #
 # WARNING: If make attempts to include a file that does not exist, it will
 # exit. This could cause your system to boot in an unfamiliar way.
 include /etc/rc.d/start3.mk #这里是服务依赖关系的记录文件
 #
 # Lastly, merge all the service output files into a single file.
 # Note that the order of the service output in the merged file is not
 # chronological.
 create_final_output_file :
 $(CAT) $(TMP_DIR)/$(TMPFILE_PREFIX).$(JOB).* \
 > $(FINAL_OUTPUT_FILE)
 $(RM) -f $(TMP_DIR)/$(TMPFILE_PREFIX).$(JOB).*
 
 # EOF
 
 /etc/rc.d/start3.mk 由上面的runlevel.mk决定位置名称
 httpd : network
 其中的空格必须是用TAB键打出来的
 最后修改/etc/rc.d/init.d/rc使其不再运行/etc/rc.d/rcX.d中的脚本,而去执行
 /etc/rc.d/runlevel.mk,实现服务的并行启动
 
 /etc/rc.d/init.d/rc :
 
 #!/bin/sh
 # Begin $rc_base/init.d/rc - Main Run Level Control Script
 
 # Based on rc script from LFS-3.1 and earlier.
 # Rewritten by Gerard Beekmans - [email protected]
 
 . /etc/sysconfig/rc
 . $rc_functions
 
 # This sets a few default terminal options.
 stty sane
 
 # These 3 signals will not cause our script to exit
 trap "" INT QUIT TSTP
 
 [ "$1" != "" ] && runlevel=$1
 
 if [ "$runlevel" = "" ]
 then
 echo "Usage: $0 <runlevel>" >&2
 exit 1
 fi
 
 previous=$PREVLEVEL
 [ "$previous" = "" ] && previous=N
 
 if [ ! -d $rc_base/rc$runlevel.d ]
 then
 echo "$rc_base/rc$runlevel.d does not exist"
 exit 1
 fi
 
 # Attempt to stop all service started by previous runlevel,
 # and killed in this runlevel
 if [ "$previous" != "N" ]
 then
 for i in $(ls -v $rc_base/rc$runlevel.d/K* 2> /dev/null)
 do
 
 check_script_status
 
 suffix=${i#$rc_base/rc$runlevel.d/K[0-9][0-9]}
 prev_start=$rc_base/rc$previous.d/S[0-9][0-9]$suffix
 sysinit_start=$rc_base/rcsysinit.d/S[0-9][0-9]$suffix
 
 if [ "$runlevel" != "0" ] && [ "$runlevel" != "6" ]
 then
 if [ ! -f $prev_start ] && [ ! -f $sysinit_start ]
 then
 echo -n -e $WARNING
 echo "$i can't be executed because it was"
 echo "not started in the previous runlevel ($previous)"
 echo -n -e $NORMAL
 continue
 fi
 fi
 $i stop
 error_value=$?
 
 if [ "$error_value" != "0" ]
 then
 print_error_msg
 fi
 done
 fi
 ################# 由于我都是从文本模式登陆,所以加上判断句,如果
 ##runlevel为3的话,就去执行runlevel.mk,而不逐一执行这些脚本
 if [ "$runlevel" = 3 ]
 then
 
 make -j -f /etc/rc.d/runlevel.mk RUNLEVEL=3 JOB=start
 # -j 表示以并行的方式去启动在runlevel.mk中定义的服务
 # -f 指定MakeFile为runlevel.mk,否则make只会去尝试去运行
 #当前目录下的MakeFile.RUNLEVEL=3在这里没有任何意义,因为
 #我没有使用$runlevel可以在任何run-level下并行服务
 #
 #JOB=start表示去start /etc/rc.d/rc3.d中的服务
 
 else
 
 #如果启动级别不是3的话,仍然按照正常去引导系统.
 #这样就不用写stop的脚本,我只想让系统启动的更快些
 #因为lfs的启动脚本比较怪,它不象其他的发行版使用/etc/rc.d/rc.sysinit
 #作为系统的初始化,而是把那些过程分开成几个脚本运行
 #si::sysinit:/etc/rc.d/init.d/rc sysinit 传入的sysinit参数去执行
 #/etc/rc.d/rcsysinit.d目录下的脚本,这样我就不能轻易的使用$runlevel
 #去使在任何运行级别都可以并行服务了,它会传进来个sysinit @_@
 #
 for i in $( ls -v $rc_base/rc$runlevel.d/S* 2> /dev/null)
 
 do
 
 if [ "$previous" != "N" ]
 then
 suffix=${i#$rc_base/rc$runlevel.d/S[0-9][0-9]}
 stop=$rc_base/rc$runlevel.d/K[0-9][0-9]$suffix
 prev_start=$rc_base/rc$previous.d/S[0-9][0-9]$suffix
 
 [ -f $prev_start ] && [ ! -f $stop ] && continue
 fi
 
 check_script_status
 
 case $runlevel in
 0|6) $i stop ;;
 *) $i start ;;
 esac
 error_value=$?
 
 if [ "$error_value" != "0" ]
 then
 print_error_msg
 fi
 done
 fi
 # End $rc_base/init.d/rc
 
 另外要修改rc脚本时,要注意语法。修改后用sh -n rc 测试有没有语法错误
 并且这个rc位置也是由/etc/inittab决定的
 如果MDK中rc就是在/etc/rc.d下。
 l3:3:wait:/etc/rc.d/rc 3
 另外哪位大侠知道这个变量是在哪里定义的阿?找了半天也没找到。
 previous=$PREVLEVEL
 
 一点小笔记,希望对你有帮助
 | 
 |