Introduction to the background

This article briefly describes the systemd process under Linux startup process, kernel source code refer to 2.6.34.

Start the process

  • The x86_64_start_kernel/i386_start_kernel function is called after the architecture-related assembly code completes the specific initialization, which in turn calls start_kernel to start the initialization of the kernel.
  • A brief overview of the execution process for root filesystem mounts in the start_kernel function is as follows:
Start_kernel () ->vfs_caches_init() ->mnt_init() ->init_rootfs() ->init_mount_tree() ->init_rootfs() ->init_mount_tree() - > mount_fs () / / mount rootfs file system - > rest_init () - > kernel_init () - > do_basic_setup () - >... ->populate_rootfs() ->prepare_namespace() ->initrd_load() ->init_post() -> initrd_post () -> initrd_post () -> initrd_post () ->initrd_load() -> initrd_post () ->run_init_process() // Execute the init user-space process // code at /init/main.c asmlinkage void __init start_kernel(void) {... vfs_caches_init(totalram_pages); . rest_init(); . } static void rest_init(void) { int pid; // Scheduler_starting (); // Scheduler_starting (); // Scheduler_starting (); // Scheduler_starting (); kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); numa_default_policy(); / / create a kernel space for kernel scheduling process pid = kernel_thread (kthreadd, NULL, CLONE_FS | CLONE_FILES); rcu_read_lock(); kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns); rcu_read_unlock(); unlock_kernel(); // create an idle process with PID 0 to execute cpu_idle() when the CPU is idle; }
  • The vfs_caches_init function creates the VFS root directory and initializes and mounts the rootfs file system.
  • The rest_init function creates three processes in turn, namely idle process, init process and kthreadd process.
Static int kernel_init(void * unused) {do_basic_setup(); static int kernel_init(void * unused); // Open the console device, copy it twice, get the 0,1,2 descriptors, standard input, standard output, If (sys_open((const char __user *) "/dev/console", O_RDWR, O_RDWR, O_RDWR, O_RDWR, O_RDWR) 0) < 0) printk(KERN_WARNING "Warning: unable to open an initial console.\n"); (void) sys_dup(0); (void) sys_dup(0); // Start the /init file in the root initramfs filesystem. Systemd is the if (! ramdisk_execute_command) ramdisk_execute_command = "/init"; if (sys_access((const char __user *) ramdisk_execute_command, 0) ! = 0) { ramdisk_execute_command = NULL; prepare_namespace(); } // Start the init process by executing ramdisk_execute_command init_post() above; }
  • The do_basic_setup function is called in the kernel_init function. If the kernel supports the initrd filesystem, the populate_rootfs function will be compiled into the kernel and called.
  • The populate_rootfs function calls unpack_to_rootfs to decompress the initramfs filesystem into the root directory of the rootfs, which must be included/initExecutable file;
  • If it is an initrd of type ramdisk, the external initrd filesystem is read to the specified address in memory through the bootloader, and then decompressed to the rootfs filesystem in the populate_rootfs function/initrd.image;
  • The SYS_ACCESS determination is used in the KERNEL_INIT function/initPrepare_Namespace function is performed if it exists on the file system currently mounted. If it does not, it is considered to be an initrd of type ramdisk.
Void __initPrepare_Namespace (void) {/init/do_mounts.c void __init Prepare_Namespace (void) {... // Convert device name to device number and save ROOT_DEV = name_to_dev_t(root_device_name); . if (initrd_load()) goto out; Out: // Replace rootfs with the root of the new root file system, making it the root directory of Linux VFS sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); } int __init initrd_load(void) {// Whether to load the initrd flag, default is 1, when the kernel startup parameter contains the noinitrd string, Mount t_initrd is set to 0 if (mount_initrd) {// create a device file, free the ramdisk initrd file system into memory, and load /initrd.image with the following function: Create_dev ("/dev/ram", Root_RAM0) created in populate_rootfs phase; // If the final root file system specified in the kernel boot parameter is the memory file system that was created, it will not be processed. Linuxrc if (rd_load_image("/initrd.image") &&root_dev! = Root_RAM0) { sys_unlink("/initrd.image"); handle_initrd(); return 1; } } sys_unlink("/initrd.image"); return 0; }
  • The prepare_namespace function parses firstroot=Parameters to convert the specified mount Settings to a device number and save them to the ROOT_DEV variable;
  • The initrd_load function starts by creating a device in rootfs with the device number Root_RAM0/dev/ram0;
  • Rd_load_image unzips it from the populate_rootfs function/initrd.imageIs written to the rootfs file system/dev/ram0;
  • ifroot=Handle_initrd is executed if the mounted device specified by the parameter is different from Root_RAM0. This function mainly starts kernel thread execution/linuxrc;
  • Follow these steps to mount the root file system, and then call the init_post function;
// static int init_post(void) {// static int init_post(void) {... if (ramdisk_execute_command) { run_init_process(ramdisk_execute_command); printk(KERN_WARNING "Failed to execute %s\n", ramdisk_execute_command); } if (execute_command) { run_init_process(execute_command); printk(KERN_WARNING "Failed to execute %s. Attempting " "defaults... \n", execute_command); } run_init_process("/sbin/init"); run_init_process("/etc/init"); run_init_process("/bin/init"); run_init_process("/bin/sh"); panic("No init found. Try passing init= option to kernel. " "See Linux Documentation/init.txt for guidance."); } static void run_init_process(char *init_filename) { argv_init[0] = init_filename; // Kernel_execve (init_filename, argv_init, envp_init); // Kernel_execve (init_filename, argv_init, envp_init); }
  • The execute_command parameter is the init parameter parsed from the kernel parameter list;
  • If the root file system is not of type initramfs, ramdisk_execute_command is NULL, so the executable specified by the init parameter or is executed first/sbin/init;
  • Otherwise, it executes directly in the rootfs file system/initExecutable program;
  • Follow the above steps to find the user process to start. If none of the kernel can be found, the startup will fail. Panic exception.

Start the systemd

  • /boot/initrd.img is a cpio format initramfs file system; /boot/initrd.img is an initramfs file system.
  • After unzipping with the cpio tool, you can see:
Drwxrwxr-x 12 Alan Alan 4096 March 12 09:57./ DRWXRWXRWT 19 Root Root 4096 March 12 14:22.. / LRWXRWXRWX 1 Alan Alan 7 March 12 09:57 bin-> usr/bin/ drwxr-xr-x 2 Alan Alan 4096 March 12 09:55 dev/ drwxr-xr-x 12 Alan Alan 4096 March 12 09:57 etc/ LRWXRWXRWX 1 Alan Alan 23 March 12 09:57 init -> usr/lib/systemd/systemd* LRWXRWXRWX 1 Alan Alan 7 March 12 09:57 lib-> usr/lib/ LRWXRWXRWX 1 Alan Alan 9 March 12 09:57 lib64 -> usr/lib64/
  • You can see that in fact/initThe executable is a symbolic link to systemd, so the user process that executes in the init_post function is systemd;
  • When making the initramfs root file system, package the systemd program into it and create/initA soft link to systemd to start systemd;
  • After systemd starts, the subsequent Linux operating system loading process is completed.