Section 8.6. The init Thread (or Process 1)


8.6. The init Thread (or Process 1)

We now explore the init thread. Note that we skip over all SMP-related routines for brevity:

 ---------------------------------------------------------------------- init/main.c 601  static int init(void * unused) 602  { 603   lock_kernel();  ... 612   child_reaper = current; ... 627   populate_rootfs(); 629   do_basic_setup(); ... 635   if (sys_access((const char __user *) "/init", 0) == 0) 636    execute_command = "/init"; 637   else 638    prepare_namespace(); ... 645   free_initmem(); 646   unlock_kernel(); 647   system_state = SYSTEM_RUNNING; 649   if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) 650    printk("Warning: unable to open an initial console.\n"); 651  652   (void) sys_dup(0); 653   (void) sys_dup(0); ... 662   if (execute_command) 663    run_init_process(execute_command); 664 665   run_init_process("/sbin/init"); 666   run_init_process("/etc/init"); 667   run_init_process("/bin/init"); 668   run_init_process("/bin/sh"); 669    670   panic("No init found. Try passing init= option to kernel."); 671  } ----------------------------------------------------------------------- 

Line 612

The init thread is set to reap any thread whose parent has died. The child_reaper variable is a global pointer to a task_struct and is defined in init/main.c. This variable comes into play in "reparenting functions" and is used as a reference to the thread that should become the new parent. We refer to functions such as reparent_to_init() (kernel/exit.c), choose_new_parent() (kernel/exit.c), and forget_original_parent() (kernel/exit.c) because they use child_reaper to reset the calling thread's parent.

Line 629

The do_basic_setup() function initializes the driver model, the sysctl interface, the network socket interface, and work queue support:

 ---------------------------------------------------------------------- init/main.c 551  static void __init do_basic_setup(void) 552  { 553   driver_init(); 554   555  #ifdef CONFIG_SYSCTL 556    sysctl_init(); 557  #endif ...  560   sock_init(); 561   562   init_workqueues(); 563   do_initcalls(); 564  } ---------------------------------------------------------------------- 

Line 553

The driver_init() (drivers/base/init.c) function initializes all the subsystems involved in driver support. This is the first part of device driver initializations. The second comes on line 563 with the call to do_initcalls().

Lines 555557

The sysctl interface provides support for dynamic alteration of kernel parameters. This means that the kernel parameters that sysctl supports can be modified at runtime without the need for recompiling and rebooting the kernel. sysctl_init() (kernel/sysctl.c) initializes the interface. For more information on sysctl, read the man page (man sysctl).

Line 560

The sock_init() function is a dummy function with a simple printk if the kernel is configured without net support. In this case, sock_init() is defined in net/nonet.c. In the case that network support is configured then sock_init() is defined in net/socket.c, it initializes the memory caches to be used for network support and registers the filesystem that supports networking.

Line 562

The call to init_workqueues sets up the work queue notifier chain. Chapter 10, "Adding Your Code to the Kernel," discusses work queues.

Line 563

The do_initcalls() (init/main.c) function constitutes the second part of device driver initialization. This function sequentially calls the entries in an array of function pointers that correspond to built-in device initialization functions.[11]

[11] Refer to http://geek.vtnet.ca/doc/initcall/ for an excellent distillation of the initcall mechanism by Trevor Woerner.

Lines 635638

If an early user space init exists, the kernel does not prepare the namespace; it allows it to perform this function. Otherwise, the call to prepare_namespace() is made. A namespace refers to the mount point of a filesystem hierarchy:

 ---------------------------------------------------------------------- init/do_mounts.c   383  void __init prepare_namespace(void) 384  { 385   int is_floppy; 386   387   mount_devfs(); ... 391   if (saved_root_name[0]) { 392    root_device_name = saved_root_name; 393    ROOT_DEV = name_to_dev_t(root_device_name); 394    if (strncmp(root_device_name, "/dev/", 5) == 0) 395     root_device_name += 5; 396   } 397    398   is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;   399 400   if (initrd_load()) 401    goto out; 402   403   if (is_floppy && rd_doload && rd_load_disk(0)) 404    ROOT_DEV = Root_RAM0; 405   406   mount_root(); 407  out: 408   umount_devfs("/dev"); 409   sys_mount(".", "/", NULL, MS_MOVE, NULL); 410   sys_chroot("."); 411   security_sb_post_mountroot(); 412   mount_devfs_fs (); 413  } ---------------------------------------------------------------------- 

Line 387

The mount_devfs() function creates the /dev mount-related structures. We need to mount /dev because we use it to refer to the root device name.

Lines 391396

This code block sets the global variable ROOT_DEV to the indicated root device as passed in through kernel boot-time parameters.

Line 398

A simple comparison of major numbers indicates whether the root device is a floppy.

Lines 400401

The call to initrd_load() mounts the RAM disk if a RAM disk has been indicated as the kernel's root filesystem. If this is the case, it returns a 1 and executes the jump to the out label, which undoes all we've done in preparation of a root filesystem from a device.

Line 406

The call to mount_root does the majority of the root-filesystem mounting. Let's closely look at this function:

 ---------------------------------------------------------------------- init/do_mounts.c 353  void __init mount_root(void) 354  { 355  #ifdef CONFIG_ROOT_NFS 356   if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { 357    if (mount_nfs_root()) 358     return; 359   360    printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); 361    ROOT_DEV = Root_FD0; 362   } 363  #endif 364  #ifdef CONFIG_BLK_DEV_FD 365   if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { ... 367    if (rd_doload==2) { 368     if (rd_load_disk(1)) { 369       ROOT_DEV = Root_RAM1; 370       root_device_name = NULL; 371     } 372    } else 373     change_floppy("root floppy"); 374   } 375  #endif 376   create_dev("/dev/root", ROOT_DEV, root_device_name); 377   mount_block_root("/dev/root", root_mountflags); 378  } ---------------------------------------------------------------------- 

Lines 355358

If the kernel has been configured to mount an NFS filesystem, we execute mount_nfs_root(). If the NFS mount fails, the kernel prints out the appropriate message and then proceeds to try to mount the floppy as the root filesystem.

Lines 364375

In this code block, the kernel tries to mount the root floppy.[12]

[12] A note on rd_doload: This global variable holds a value of 0 if no RAM disk is to be loaded, a value of 1 if a RAM disk is to be loaded, and a value of 2 for a "dual initrd/ramload setup."

Line 377

This function performs the bulk of the root device mounting. We now return to init().

Line 645

The call to free_initmem() frees all memory segments that the routines used up with the __init precursor. This marks our exit from pure kernel space and we begin to set up user mode data.

Lines 649650

Open up the initial console.

Lines 662668

The execute_command variable is set in init_setup() and holds the value of a boot-time parameter that contains the name of the init program to call if we do not want the default /sbin/init to be called. If an init program name is passed, it takes priority over the usual /sbin/init. Note that the call to run_init_process() (init/main.c) does not return because it ends with a call to execve(). Thus, the first init function call to run successfully is the only one run. In the case that an init program is not found, we can use the bash shell to start up.

Line 670

This panic statement should be reached only if all of our tries to execute various init program fails.

This concludes kernel initialization. From here on out, the init process involves itself with system initialization and starting all the necessary processes and daemon support required for user login and support.




The Linux Kernel Primer. A Top-Down Approach for x86 and PowerPC Architectures
The Linux Kernel Primer. A Top-Down Approach for x86 and PowerPC Architectures
ISBN: 131181637
EAN: N/A
Year: 2005
Pages: 134

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net