技術(shù)員聯(lián)盟提供win764位系統(tǒng)下載,win10,win7,xp,裝機純凈版,64位旗艦版,綠色軟件,免費軟件下載基地!

當(dāng)前位置:主頁 > 教程 > 服務(wù)器類 >

linux根文件系統(tǒng)的掛載過程詳解

來源:技術(shù)員聯(lián)盟┆發(fā)布時間:2017-11-15 12:16┆點擊:

  st1\:*{behavior:url(#ieooui) }

  一:前言

  前段時間在編譯kernel的時候發(fā)現(xiàn)rootfs掛載不上。相同的root選項設(shè)置舊版的image卻可以。為了徹底解決這個問題。研究了一下rootfs的掛載過程。特總結(jié)如下,希望能給這部份知識點比較迷茫的朋友一點幫助。

  二:rootfs的種類

  總的來說,rootfs分為兩種:虛擬rootfs和真實rootfs.現(xiàn)在kernel的發(fā)展趨勢是將更多的功能放到用戶空間完成。以保持內(nèi)核的精簡。虛擬rootfs也是各linux發(fā)行廠商普遍采用的一種方式??梢詫⒁徊糠莸某跏蓟ぷ鞣旁谔摂M的rootfs里完成。然后切換到真實的文件系統(tǒng).

  在虛擬rootfs的發(fā)展過程中。又有以下幾個版本:

  initramfs:

  Initramfs是在 kernel 2.5中引入的技術(shù),實際上它的含義就是:在內(nèi)核鏡像中附加一個cpio包,這個cpio包中包含了一個小型的文件系統(tǒng),當(dāng)內(nèi)核啟動時,內(nèi)核將這個cpio包解開,并且將其中包含的文件系統(tǒng)釋放到rootfs中,內(nèi)核中的一部分初始化代碼會放到這個文件系統(tǒng)中,作為用戶層進程來執(zhí)行。這樣帶來的明顯的好處是精簡了內(nèi)核的初始化代碼,而且使得內(nèi)核的初始化過程更容易定制。這種這種方式的rootfs是包含在kernel image之中的.

  cpio-initrd: cpio格式的rootfs

  image-initrd:傳統(tǒng)格式的rootfs

  關(guān)于這兩種虛擬文件系統(tǒng)的制作請自行參閱其它資料

  三:rootfs文件系統(tǒng)的掛載過程

  這里說的rootfs不同于上面分析的rootfs。這里指的是系統(tǒng)初始化時的根結(jié)點。即/結(jié)點。它是其于內(nèi)存的rootfs文件系統(tǒng)。這部份之前在>和文件系統(tǒng)中已經(jīng)分析過。為了知識的連貫性這里再重復(fù)一次。

  Start_kernel()àmnt_init():

  void __init mnt_init(void)

  {

  ……

  ……

  init_rootfs();

  init_mount_tree();

  }

  Init_rootfs的代碼如下:

  int __init init_rootfs(void)

  {

  int err;

  err = bdi_init(&ramfs_backing_dev_info);

  if (err)

  return err;

  err = register_filesystem(&rootfs_fs_type);

  if (err)

  bdi_destroy(&ramfs_backing_dev_info);

  return err;

  }

  這個函數(shù)很簡單。就是注冊了rootfs的文件系統(tǒng).

  init_mount_tree()代碼如下:

  static void __init init_mount_tree(void)

  {

  struct vfsmount *mnt;

  struct mnt_namespace *ns;

  struct path root;

  mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);

  if (IS_ERR(mnt))

  panic("Can't create rootfs");

  ns = kmalloc(sizeof(*ns), GFP_KERNEL);

  if (!ns)

  panic("Can't allocate initial namespace");

  atomic_set(&ns->count, 1);

  INIT_LIST_HEAD(&ns->list);

  init_waitqueue_head(&ns->poll);

  ns->event = 0;

  list_add(&mnt->mnt_list, &ns->list);

  ns->root = mnt;

  mnt->mnt_ns = ns;

  init_task.nsproxy->mnt_ns = ns;

  get_mnt_ns(ns);

  root.mnt = ns->root;

  root.dentry = ns->root->mnt_root;

  set_fs_pwd(current->fs, &root);

  set_fs_root(current->fs, &root);

  }

  在這里,將rootfs文件系統(tǒng)掛載。它的掛載點默認(rèn)為”/”.最后切換進程的根目錄和當(dāng)前目錄為”/”.這也就是根目錄的由來。不過這里只是初始化。等掛載完具體的文件系統(tǒng)之后,一般都會將根目錄切換到具體的文件系統(tǒng)。所以在系統(tǒng)啟動之后,用mount命令是看不到rootfs的掛載信息的.

  四:虛擬文件系統(tǒng)的掛載

  根目錄已經(jīng)掛上去了,可以掛載具體的文件系統(tǒng)了.

  在start_kernel()àrest_init()àkernel_init():

  static int __init kernel_init(void * unused)

  {

  ……

  ……

  do_basic_setup();

  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();

  }

  /*

  * Ok, we have completed the initial bootup, and

  * we're essentially up and running. Get rid of the

  * initmem segments and start the user-mode stuff..

  */

  init_post();

  return 0;

  }

  do_basic_setup()是一個很關(guān)鍵的函數(shù),所有直接編譯在kernel中的模塊都是由它啟動的。代碼片段如下:

  static void __init do_basic_setup(void)

  {

  /* drivers will send hotplug events */

  init_workqueues();

  usermodehelper_init();

  driver_init();

  init_irq_proc();

  do_initcalls();

  }

  Do_initcalls()用來啟動所有在__initcall_start和__initcall_end段的函數(shù),而靜態(tài)編譯進內(nèi)核的modules也會將其入口放置在這段區(qū)間里。

  跟根文件系統(tǒng)相關(guān)的初始化函數(shù)都會由rootfs_initcall()所引用。注意到有以下初始化函數(shù):

  rootfs_initcall(populate_rootfs);

  也就是說會在系統(tǒng)初始化的時候會調(diào)用populate_rootfs進行初始化。代碼如下:

  static int __init populate_rootfs(void)

  {

  char *err = unpack_to_rootfs(__initramfs_start,

  __initramfs_end - __initramfs_start, 0);

  if (err)

  panic(err);

  if (initrd_start) {

  #ifdef CONFIG_BLK_DEV_RAM

  int fd;

  printk(KERN_INFO "checking if image is initramfs...");

  err = unpack_to_rootfs((char *)initrd_start,

  initrd_end - initrd_start, 1);

  if (!err) {

  printk(" it is\n");

  unpack_to_rootfs((char *)initrd_start,

  initrd_end - initrd_start, 0);

  free_initrd();

  return 0;

  }

  printk("it isn't (%s); looks like an initrd\n", err);

  fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);

  if (fd >= 0) {

  sys_write(fd, (char *)initrd_start,

  initrd_end - initrd_start);

  sys_close(fd);

  free_initrd();

  }

  #else

  printk(KERN_INFO "Unpacking initramfs...");

  err = unpack_to_rootfs((char *)initrd_start,

  initrd_end - initrd_start, 0);

  if (err)

  panic(err);

  printk(" done\n");

  free_initrd();

  #endif

  }

  return 0;

  }