| 安裝根文件系統(tǒng)式系統(tǒng)初始化的關(guān)鍵部分。Linux內(nèi)核允許根文件系統(tǒng)放在很多不同的地方,比如硬盤分區(qū)、軟盤、通過(guò)NFS共享的遠(yuǎn)程文件系統(tǒng)以及保存在ramdisk中。內(nèi)核要在變量ROOT_DEV中尋找包含根文件系統(tǒng)的磁盤主設(shè)備號(hào)。當(dāng)編譯內(nèi)核時(shí),或者像最初的啟動(dòng)裝入程序傳遞一個(gè)合適的“root”選項(xiàng)時(shí),根文件系統(tǒng)可以被指定為/dev目錄下的一個(gè)設(shè)備文件。 相關(guān)閱讀: http://www./Linux/2012-02/53771.htm 安裝根文件系統(tǒng)分為兩個(gè)階段: 1,內(nèi)核安裝特殊rootfs文件系統(tǒng),該文件系統(tǒng)僅提供一個(gè)作為初始安裝點(diǎn)的空目錄 start_kernel()->vfs_caches_init()->mnt_init()->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;   
}   
static struct backing_dev_info ramfs_backing_dev_info = {   
    .name       = "ramfs",   
    .ra_pages   = 0,       
    .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK |   
              BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |   
              BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,   
};   
  
  
  
  
  
  
  
  
  
  
  
   
    
int register_filesystem(struct file_system_type * fs)   
{   
    int res = 0;   
    struct file_system_type ** p;   
   
    BUG_ON(strchr(fs->name, '.'));   
    if (fs->next)   
        return -EBUSY;   
    INIT_LIST_HEAD(&fs->fs_supers);   
    write_lock(&file_systems_lock);   
       
    p = find_filesystem(fs->name, strlen(fs->name));   
    if (*p)   
        res = -EBUSY;   
    else   
        *p = fs;   
    write_unlock(&file_systems_lock);   
    return res;   
}   根文件系統(tǒng)定義如下 
static struct file_system_type rootfs_fs_type = {   
    .name       = "rootfs",   
    .get_sb     = rootfs_get_sb,   
    .kill_sb    = kill_litter_super,   
};   下面看看他的兩個(gè)函數(shù) 
   
static int rootfs_get_sb(struct file_system_type *fs_type,   
    int flags, const char *dev_name, void *data, struct vfsmount *mnt)   
{   
    return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,   
                mnt);   
}   
int get_sb_nodev(struct file_system_type *fs_type,   
    int flags, void *data,   
    int (*fill_super)(struct super_block *, void *, int),   
    struct vfsmount *mnt)   
{   
    int error;   
       
    struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);   
   
    if (IS_ERR(s))   
        return PTR_ERR(s);   
   
    s->s_flags = flags;   
       
    error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);   
    if (error) {   
        deactivate_locked_super(s);   
        return error;   
    }   
    s->s_flags |= MS_ACTIVE;   
    simple_set_mnt(mnt, s);   
    return 0;   
}   
  
  
  
  
  
  
   
    
struct super_block *sget(struct file_system_type *type,   
            int (*test)(struct super_block *,void *),   
            int (*set)(struct super_block *,void *),   
            void *data)   
{   
    struct super_block *s = NULL;   
    struct super_block *old;   
    int err;   
   
retry:   
    spin_lock(&sb_lock);   
    if (test) {   
        list_for_each_entry(old, &type->fs_supers, s_instances) {   
            if (!test(old, data))   
                continue;   
            if (!grab_super(old))   
                goto retry;   
            if (s) {   
                up_write(&s->s_umount);   
                destroy_super(s);   
            }   
            return old;   
        }   
    }   
    if (!s) {   
        spin_unlock(&sb_lock);   
        s = alloc_super(type);   
        if (!s)   
            return ERR_PTR(-ENOMEM);   
        goto retry;   
    }   
           
    err = set(s, data);   
    if (err) {   
        spin_unlock(&sb_lock);   
        up_write(&s->s_umount);   
        destroy_super(s);   
        return ERR_PTR(err);   
    }   
       
    s->s_type = type;   
    strlcpy(s->s_id, type->name, sizeof(s->s_id));   
       
    list_add_tail(&s->s_list, &super_blocks);   
    list_add(&s->s_instances, &type->fs_supers);   
    spin_unlock(&sb_lock);   
    get_filesystem(type);   
    return s;   
}           static struct super_block *alloc_super(struct file_system_type *type)  {               struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);      static const struct super_operations default_op;        if (s) {          if (security_sb_alloc(s)) {              kfree(s);              s = NULL;              goto out;          }                    INIT_LIST_HEAD(&s->s_files);          INIT_LIST_HEAD(&s->s_instances);          INIT_HLIST_HEAD(&s->s_anon);          INIT_LIST_HEAD(&s->s_inodes);          INIT_LIST_HEAD(&s->s_dentry_lru);          init_rwsem(&s->s_umount);          mutex_init(&s->s_lock);          lockdep_set_class(&s->s_umount, &type->s_umount_key);                        lockdep_set_class(&s->s_lock, &type->s_lock_key);                                  down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);          s->s_count = S_BIAS;          atomic_set(&s->s_active, 1);          mutex_init(&s->s_vfs_rename_mutex);          mutex_init(&s->s_dquot.dqio_mutex);          mutex_init(&s->s_dquot.dqonoff_mutex);          init_rwsem(&s->s_dquot.dqptr_sem);          init_waitqueue_head(&s->s_wait_unfrozen);          s->s_maxbytes = MAX_NON_LFS;          s->dq_op = sb_dquot_ops;          s->s_qcop = sb_quotactl_ops;          s->s_op = &default_op;          s->s_time_gran = 1000000000;      }  out:      return s;  }  
kill_litter_super的過(guò)程相反,這里不再寫了。 構(gòu)造根目錄是由init_mount_tree()函數(shù)實(shí)現(xiàn)的,該函數(shù)在前面已經(jīng)介紹過(guò)了。 
 2,安裝實(shí)際根文件系統(tǒng) 關(guān)于__setup宏 __setup宏來(lái)注冊(cè)關(guān)鍵字及相關(guān)聯(lián)的處理函數(shù),__setup宏在include/linux/init.h中定義,其原型如下:__setup(string, _handler);
 其中:string是關(guān)鍵字,_handler是關(guān)聯(lián)處理函數(shù)。__setup只是告訴內(nèi)核在啟動(dòng)時(shí)輸入串中含有string時(shí),內(nèi)核要去
 執(zhí)行_handler。String必須以“=”符結(jié)束以使parse_args更方便解析。緊隨“=”后的任何文本都會(huì)作為輸入傳給
 _handler。下面的例子來(lái)自于init/do_mounts.c,其中root_dev_setup作為處理程序被注冊(cè)給“root=”關(guān)鍵字:
 __setup("root=", root_dev_setup);
 比如我們?cè)趩?dòng)向參數(shù)終有   noinitrd root=/dev/mtdblock2 console=/linuxrc  setup_arch解釋時(shí)會(huì)發(fā)現(xiàn)root=/dev/mtdblock2,然后它就會(huì)調(diào)用root_dev_setup static int __init root_dev_setup(char *line)  {      strlcpy(saved_root_name, line, sizeof(saved_root_name));      return 1;  }    __setup("root=", root_dev_setup);  
Start_kernel->rest_init->init-> prepare_namespace->
     void __init prepare_namespace(void)  {      int is_floppy;        if (root_delay) {          printk(KERN_INFO "Waiting %dsec before mounting root device...\n",                 root_delay);          ssleep(root_delay);      }                    wait_for_device_probe();            md_run_setup();        if (saved_root_name[0]) {          root_device_name = saved_root_name;          if (!strncmp(root_device_name, "mtd", 3) ||              !strncmp(root_device_name, "ubi", 3)) {              mount_block_root(root_device_name, root_mountflags);              goto out;          }                    ROOT_DEV = name_to_dev_t(root_device_name);          if (strncmp(root_device_name, "/dev/", 5) == 0)              root_device_name += 5;      }        if (initrd_load())          goto out;              if ((ROOT_DEV == 0) && root_wait) {          printk(KERN_INFO "Waiting for root device %s...\n",              saved_root_name);          while (driver_probe_done() != 0 ||              (ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)              msleep(100);          async_synchronize_full();      }        is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;        if (is_floppy && rd_doload && rd_load_disk(0))          ROOT_DEV = Root_RAM0;            mount_root();  out:      devtmpfs_mount("dev");      sys_mount(".", "/", NULL, MS_MOVE, NULL);            sys_chroot(".");  }  
 mount_root操作 void __init mount_root(void)  {  #ifdef CONFIG_ROOT_NFS       if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {          if (mount_nfs_root())              return;            printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");          ROOT_DEV = Root_FD0;      }  #endif   #ifdef CONFIG_BLK_DEV_FD       if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {                    if (rd_doload==2) {              if (rd_load_disk(1)) {                  ROOT_DEV = Root_RAM1;                  root_device_name = NULL;              }          } else              change_floppy("root floppy");      }  #endif   #ifdef CONFIG_BLOCK/*這里是一般流程*/       create_dev("/dev/root", ROOT_DEV);      mount_block_root("/dev/root", root_mountflags);  #endif   }  
void __init mount_block_root(char *name, int flags)  {            char *fs_names = __getname_gfp(GFP_KERNEL          | __GFP_NOTRACK_FALSE_POSITIVE);      char *p;  #ifdef CONFIG_BLOCK       char b[BDEVNAME_SIZE];  #else       const char *b = name;  #endif               get_fs_names(fs_names);  retry:      for (p = fs_names; *p; p += strlen(p)+1) {                      int err = do_mount_root(name, p, flags, root_mount_data);          switch (err) {              case 0:                  goto out;              case -EACCES:                  flags |= MS_RDONLY;                  goto retry;              case -EINVAL:                  continue;          }                    #ifdef CONFIG_BLOCK           __bdevname(ROOT_DEV, b);  #endif           printk("VFS: Cannot open root device \"%s\" or %s\n",                  root_device_name, b);          printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");            printk_all_partitions();  #ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT           printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify "                 "explicit textual name for \"root=\" boot option.\n");  #endif           panic("VFS: Unable to mount root fs on %s", b);      }        printk("List of all partitions:\n");      printk_all_partitions();      printk("No filesystem could mount root, tried: ");      for (p = fs_names; *p; p += strlen(p)+1)          printk(" %s", p);      printk("\n");  #ifdef CONFIG_BLOCK       __bdevname(ROOT_DEV, b);  #endif       panic("VFS: Unable to mount root fs on %s", b);  out:      putname(fs_names);  }     
static int __init do_mount_root(char *name, char *fs, int flags, void *data)  {            int err = sys_mount(name, "/root", fs, flags, data);      if (err)          return err;            sys_chdir("/root");      ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev;      printk("VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",             current->fs->pwd.mnt->mnt_sb->s_type->name,             current->fs->pwd.mnt->mnt_sb->s_flags & MS_RDONLY ?             " readonly" : "", MAJOR(ROOT_DEV), MINOR(ROOT_DEV));      return 0;  }  
到此,根文件系統(tǒng)的安裝過(guò)程算是完成了,中間關(guān)于mount等系統(tǒng)調(diào)用將在后面分析??梢钥闯隹偟牟襟E主要有: 1,創(chuàng)建一個(gè)rootfs,這個(gè)是虛擬的rootfs,是內(nèi)存文件系統(tǒng)(和ramfs),后面還會(huì)指向具體的根文件系統(tǒng); 2,從系統(tǒng)啟動(dòng)參數(shù)中獲取設(shè)備文件名以及設(shè)備號(hào); 3,調(diào)用系統(tǒng)調(diào)用創(chuàng)建符號(hào)鏈接,并調(diào)用mount系統(tǒng)調(diào)用進(jìn)程實(shí)際的安裝操作; 4,改變進(jìn)程當(dāng)前目錄; 5,移動(dòng)rootfs文件系統(tǒng)根目錄上得已經(jīng)安裝文件系統(tǒng)的安裝點(diǎn);rootfs特殊文件系統(tǒng)沒(méi)有被卸載,他只是隱藏在基于磁盤的根文件系統(tǒng)下了。
 |