《Linux启动过程分析》init进程挂载其他重要文件系统

来源:互联网 发布:奥鹏教育教师网络培训 编辑:程序博客网 时间:2024/04/29 14:12

说明:本分析基于Linux2.6内核和Android2.3版本,其他版本仅供参考。

Android2.3及Linux2.6.29内核模拟器版本编译与调试

一、前言

  从前边Linux内核启动之根文件系统挂载分析一文我们分析到Linux内核启动之后的根文件系统要么是rootfs(ramdisk释放到rootfs后,其根目录存在init的情况下),要么是磁盘等文件系统;系统根目录要么是rootfs的根目录,要么是磁盘的根目录。

  但我们一直特别关心的设备文件系统、proc文件系统,还有就是Linux2.6内核引入的与设备驱动息息相关的sysfs文件系统都是怎样挂载到系统的根目录的?

  下边我们就通过sysfs文件系统的创建、挂载到自己根目录,以及最后又如何挂载到系统/sys目录的过程做简单分析;其他文件系统的挂载类似,就不再做分析。

二、sysfs文件系统创建和挂载到自己的根目录

跟Linux内核启动之根文件系统挂载分析中一样,我们先从Linux内核启动代码看起:

kernel/init/main.c

asmlinkage void __init start_kernel(void){  setup_arch(&command_line);//解析uboot命令行,实际文件系统挂载需要  parse_args("Booting kernel", static_command_line, __start___param,   __stop___param - __start___param,   &unknown_bootoption);  vfs_caches_init(num_physpages);#ifdef CONFIG_PROC_FS  //proc文件系统的创建  proc_root_init();#endif  rest_init();  /*  static int __init kernel_init(void * unused);  do_basic_setup();  //加载内核静态模块  do_initcalls();  mm/shmem.c  module_init(init_tmpfs);  //dev设备文件系统的创建  register_filesystem(&tmpfs_fs_type);  static struct file_system_type tmpfs_fs_type = {    .owner= THIS_MODULE,    .name= "tmpfs",    .get_sb= shmem_get_sb,    .kill_sb= kill_litter_super,  };  */}
kernel/fs/dcache.c

void __init vfs_caches_init(unsigned long mempages){  mnt_init();  bdev_cache_init(); //块设备文件创建  chrdev_init();//字符设备文件创建}
kernel/fs/namespace.c
void __init mnt_init(void){  err = sysfs_init(); //本节主要分析这一步  init_rootfs(); //向内核注册rootfs  init_mount_tree();//重要!!!rootfs根目录的建立以及rootfs文件系统的挂载;设置系统current根目录和根文件系统为rootfs}
kernel/fs/sysfs/mount.c
int __init sysfs_init(void){  err = register_filesystem(&sysfs_fs_type);//向内核注册sysfs文件系统  sysfs_mount = kern_mount(&sysfs_fs_type);//将sysfs文件系统挂载到自己的根目录}static struct file_system_type sysfs_fs_type = {  .name= "sysfs",  .get_sb= sysfs_get_sb,  .kill_sb= kill_anon_super,};

1.sysfs文件系统如何将自己挂载到自己的根目录?

  这部分内容其实和Linux内核启动之根文件系统挂载分析中rootfs挂载自己到自己的根目录很类似;过程如下:

kernel/include/linux/fs.h

#define kern_mount(type) kern_mount_data(type, NULL)

kernel/fs/super.c

struct vfsmount *kern_mount_data(struct file_system_type *type, void *data){  return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);}struct vfsmount *vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data){  struct vfsmount *mnt;  mnt = alloc_vfsmnt(name);  //建立并填充vfsmount  error = type->get_sb(type, flags, name, data, mnt);//为文件系统建立并填充超级块(主要是其dentry和inode),建立sysfs根目录   mnt->mnt_mountpoint = mnt->mnt_root;//文件系统挂载点目录,其实就是刚才建立的”/”目录。挂载点就是自己!!!!    mnt->mnt_parent = mnt;////父对象是自己!!!!}

我们还是主要分析下超级块及根目录的建立过程:

kernel/fs/sysfs/mount.c

static int sysfs_get_sb(struct file_system_type *fs_type,int flags, const char *dev_name, void *data, struct vfsmount *mnt){  return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);}
kernel/fs/super.c
int get_sb_single(struct file_system_type *fs_type,int flags, void *data,int (*fill_super)(struct super_block *, void *, int),struct vfsmount *mnt){  //在内存中分配一个超级块  s = sget(fs_type, compare_single, set_anon_super, NULL);  //执行回调函数,填充该超级块,并建立根目录项及对应i节点  error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);  //关联超级块(包含目录项dentry和i节点inode)和vfsmount   return simple_set_mnt(mnt, s);}
kernel/fs/sysfs/mount.c
static int sysfs_fill_super(struct super_block *sb, void *data, int silent){  //i节点  struct inode *inode;  //根目录项  struct dentry *root;  //超级块  sb->s_blocksize = PAGE_CACHE_SIZE;  sb->s_blocksize_bits = PAGE_CACHE_SHIFT;  sb->s_magic = SYSFS_MAGIC;  sb->s_op = &sysfs_ops;  sb->s_time_gran = 1;  sysfs_sb = sb;  //创建i节点,这里边就是具体ops的操作;有兴趣可以细看下,在此不再分析  inode = sysfs_get_inode(&sysfs_root);  //建立上处i节点的目录项  root = d_alloc_root(inode);  //关联超级块和目录项  sb->s_root = root;  return 0;}
kernel/fs/namespace.c
int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb){  printk("TK-------_>>>>>>>namespace.c>>>>simple_set_mnt\n");//add by tankai  mnt->mnt_sb = sb;  //对 mnt_sb超级块指针附值  mnt->mnt_root = dget(sb->s_root); //对mnt_root指向的根目录赋值  return 0;}

2.驱动加载过程中就可以在操作如上sysfs,但记住此时sysfs、dev等文件系统并没有和系统current根文件系统和根目录有任何关联、这时用户空间程序是访问不到这些文件系统的。

三、sysfs文件系统挂载到系统current目录树的过程

  sysfs文件系统挂载到系统current目录树是在用户空间init进程中完成的;如下代码片段:

Android/system/core/init/init.c

int main(int argc, char **argv){  mkdir("/dev", 0755);  mkdir("/proc", 0755);  mkdir("/sys", 0755);  //设备文件系统的挂载  mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");  mkdir("/dev/pts", 0755);  mkdir("/dev/socket", 0755);  mount("devpts", "/dev/pts", "devpts", 0, NULL);  //proc文件系统的挂载  mount("proc", "/proc", "proc", 0, NULL);  //sysfs文件系统的挂载  mount("sysfs", "/sys", "sysfs", 0, NULL);}
在看看init.rc中关于其他文件系统的挂载:
# Backward compatibility    symlink /system/etc /etc    symlink /sys/kernel/debug /d# Right now vendor lives on the same filesystem as system,# but someday that may change.    symlink /system/vendor /vendor# create mountpoints    mkdir /mnt 0775 root system    mkdir /mnt/sdcard 0000 system system# Create cgroup mount point for cpu accounting    mkdir /acct    mount cgroup none /acct cpuacct    mkdir /acct/uid# Backwards Compat - XXX: Going away in G*    symlink /mnt/sdcard /sdcard    mkdir /system    mkdir /data 0771 system system    mkdir /cache 0770 system cache    mkdir /config 0500 root root    # Directory for putting things only root should see.    mkdir /mnt/secure 0700 root root    # Directory for staging bindmounts    mkdir /mnt/secure/staging 0700 root root    # Directory-target for where the secure container    # imagefile directory will be bind-mounted    mkdir /mnt/secure/asec  0700 root root    # Secure container public mount points.    mkdir /mnt/asec  0700 root system    mount tmpfs tmpfs /mnt/asec mode=0755,gid=1000    # Filesystem image public mount points.    mkdir /mnt/obb 0700 root system    mount tmpfs tmpfs /mnt/obb mode=0755,gid=1000    write /proc/sys/kernel/panic_on_oops 1    write /proc/sys/kernel/hung_task_timeout_secs 0    write /proc/cpu/alignment 4    write /proc/sys/kernel/sched_latency_ns 10000000    write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000    write /proc/sys/kernel/sched_compat_yield 1    write /proc/sys/kernel/sched_child_runs_first 0# Create cgroup mount points for process groups    mkdir /dev/cpuctl    mount cgroup none /dev/cpuctl cpu    chown system system /dev/cpuctl    chown system system /dev/cpuctl/tasks    chmod 0777 /dev/cpuctl/tasks    write /dev/cpuctl/cpu.shares 1024    mkdir /dev/cpuctl/fg_boost    chown system system /dev/cpuctl/fg_boost/tasks    chmod 0777 /dev/cpuctl/fg_boost/tasks    write /dev/cpuctl/fg_boost/cpu.shares 1024    mkdir /dev/cpuctl/bg_non_interactive    chown system system /dev/cpuctl/bg_non_interactive/tasks    chmod 0777 /dev/cpuctl/bg_non_interactive/tasks    # 5.0 %    write /dev/cpuctl/bg_non_interactive/cpu.shares 52on fs# mount mtd partitions    # Mount /system rw first to give the filesystem a chance to save a checkpoint    mount yaffs2 mtd@system /system    mount yaffs2 mtd@system /system ro remount    mount yaffs2 mtd@userdata /data nosuid nodev    mount yaffs2 mtd@cache /cache nosuid nodevon post-fs    # once everything is setup, no need to modify /    mount rootfs rootfs / ro remount

四、sysfs、rootfs与系统current根文件系统的问题

  通过以上分析,结合Linux内核启动之根文件系统挂载分析;有人可能会问为什么不用sysfs替代rootfs功能(也就是直接设置sysfs为系统current的根文件系统),这样、不就可以不需要rootfs了吗?Linux这方面的设计可能是出于安全和效率方面的考虑;不用sysfs作为系统current的根文件系统,而是增加一个rootfs专门完成初始挂载点的创建工作。



原创粉丝点击