linux文件系统挂载流程_linux磁盘分区,文件系统挂载,卸载的操作命令及流程 - CSDN
  • 前段时间在编译kernel的时候发现rootfs挂载不上。相同的root选项设置旧版的image却可以。为了彻底解决这个问题。研究了一下rootfs的挂载过程。特总结如下,希望能给这部份知识点比较迷茫的朋友一点帮助。    ...

    一:前言 

    前段时间在编译kernel的时候发现rootfs挂载不上。相同的root选项设置旧版的image却可以。为了彻底解决这个问题。研究了一下rootfs的挂载过程。特总结如下,希望能给这部份知识点比较迷茫的朋友一点帮助。 

     

    二:rootfs的种类 

    总的来说,rootfs分为两种:虚拟rootfs和真实rootfs.现在kernel的发展趋势是将更多的功能放到用户空间完成。以保持内核的精简。虚拟rootfs也是各linux发行厂商普遍采用的一种方式。可以将一部份的初始化工作放在虚拟的rootfs里完成。然后切换到真实的文件系统. 

    在虚拟rootfs的发展过程中。又有以下几个版本: 

    initramfs: 

     Initramfs是在 kernel 2.5中引入的技术,实际上它的含义就是:在内核镜像中附加一个cpio包,这个cpio包中包含了一个小型的文件系统,当内核启动时,内核将这个cpio包解开,并且将其中包含的文件系统释放到rootfs中,内核中的一部分初始化代码会放到这个文件系统中,作为用户层进程来执行。这样带来的明显的好处是精简了内核的初始化代码,而且使得内核的初始化过程更容易定制。这种这种方式的rootfs是包含在kernel image之中的. 

     

    cpio-initrd: cpio格式的rootfs

     

     

    image-initrd:传统格式的rootfs 

    关于这两种虚拟文件系统的制作请自行参阅其它资料 

     

    三:rootfs文件系统的挂载过程 

    这里说的rootfs不同于上面分析的rootfs。这里指的是系统初始化时的根结点。即/结点。它是其于内存的rootfs文件系统。这部份之前在<< linux启动过程分析>>和文件系统中已经分析过。为了知识的连贯性这里再重复一次。 

    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; 

    这个函数很简单。就是注册了rootfs的文件系统. 

    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文件系统挂载。它的挂载点默认为”/”.最后切换进程的根目录和当前目录为”/”.这也就是根目录的由来。不过这里只是初始化。等挂载完具体的文件系统之后,一般都会将根目录切换到具体的文件系统。所以在系统启动之后,用mount命令是看不到rootfs的挂载信息的. 

     

    四:虚拟文件系统的挂载 

    根目录已经挂上去了,可以挂载具体的文件系统了. 

    在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()是一个很关键的函数,所有直接编译在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段的函数,而静态编译进内核的modules也会将其入口放置在这段区间里。 

    跟根文件系统相关的初始化函数都会由rootfs_initcall()所引用。注意到有以下初始化函数: 

    rootfs_initcall(populate_rootfs); 

    也就是说会在系统初始化的时候会调用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; 

    unpack_to_rootfs:顾名思义就是解压包,并将其释放至rootfs。它实际上有两个功能,一个是释放包,一个是查看包,看其是否属于cpio结构的包。功能选择是根据最后的一个参数来区分的. 

    在这个函数里,对应我们之前分析的三种虚拟根文件系统的情况。一种是跟kernel融为一体的initramfs.在编译kernel的时候,通过链接脚本将其存放在__initramfs_start至__initramfs_end的区域。这种情况下,直接调用unpack_to_rootfs将其释放到根目录.如果不是属于这种形式的。也就是__initramfs_start和__initramfs_end的值相等,长度为零。不会做任何处理。退出. 

     

    对应后两种情况。从代码中看到,必须要配制CONFIG_BLK_DEV_RAM才会支持image-initrd。否则全当成cpio-initrd的形式处理。 

    对于是cpio-initrd的情况。直接将其释放到根目录。对于是image-initrd的情况。将其释放到/initrd.image.最后将initrd内存区域归入伙伴系统。这段内存就可以由操作系统来做其它的用途了。 

    接下来,内核对这几种情况又是怎么处理的呢?不要着急。往下看: 

     

    回到kernel_init()这个函数: 

    static int __init kernel_init(void * unused)

             ……. 

             ……. 

             do_basic_setup(); 

     

             /* 

              * check if there is an early userspace init.  If yes, let it do all

     

     

              * the work 

              */ 

     

             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; } ramdisk_execute_command:在kernel解析引导参数的时候使用。如果用户指定了init文件路径,即使用了“init=”,就会将这个参数值存放到这里。 如果没有指定init文件路径。默认为/init 对应于前面一段的分析,我们知道,对于initramdisk和cpio-initrd的情况,都会将虚拟根文件系统释放到根目录。如果这些虚拟文件系统里有/init这个文件。就会转入到init_post()。 Init_post()代码如下: static int noinline init_post(void){ free_initmem(); unlock_kernel(); mark_rodata_ro(); system_state = SYSTEM_RUNNING; numa_default_policy(); if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) printk(KERN_WARNING "Warning: unable to open an initial console./n"); (void) sys_dup(0); (void) sys_dup(0); if (ramdisk_execute_command) { run_init_process(ramdisk_execute_command); printk(KERN_WARNING "Failed to execute %s/n", ramdisk_execute_command); } /* * We try each of these until one succeeds. * * The Bourne shell can be used instead of init if we are * trying to recover a really broken machine. */ 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."); } 从代码中可以看中,会依次执行指定的init文件,如果失败,就会执行/sbin/init, /etc/init,, /bin/init,/bin/sh 注意的是,run_init_process在调用相应程序运行的时候,用的是kernel_execve。也就是说调用进程会替换当前进程。只要上述任意一个文件调用成功,就不会返回到这个函数。如果上面几个文件都无法执行。打印出没有找到init文件的错误。 对于image-hdr或者是虚拟文件系统中没有包含 /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 the known devices to complete their probing */ while (driver_probe_done() != 0) msleep(100); //mtd的处理 md_run_setup(); if (saved_root_name[0]) { root_device_name = saved_root_name; if (!strncmp(root_device_name, "mtd", 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; /* wait for any asynchronous scanning to complete */ 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); } is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; if (is_floppy && rd_doload && rd_load_disk(0)) ROOT_DEV = Root_RAM0; mount_root(); out: sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); } 这里有几个比较有意思的处理,首先用户可以用root=来指定根文件系统。它的值保存在saved_root_name中。如果用户指定了以mtd开始的字串做为它的根文件系统。就会直接去挂载。这个文件是mtdblock的设备文件。 否则将设备结点文件转换为ROOT_DEV即设备节点号,然后,转向initrd_load()执行initrd预处理后,再将具体的根文件系统挂载。注意到,在这个函数末尾。会调用sys_mount()来移动当前文件系统挂载点到”/”目录下。然后将根目录切换到当前目录。这样,根文件系统的挂载点就成为了我们在用户空间所看到的”/”了. 对于其它根文件系统的情况,会先经过initrd的处理。即 int __init initrd_load(void){ if (mount_initrd) { create_dev("/dev/ram", Root_RAM0); /* * Load the initrd data into /dev/ram0. Execute it as initrd * unless /dev/ram0 is supposed to be our actual root device, * in that case the ram disk is just set up here, and gets * mounted in the normal path. */ if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) { sys_unlink("/initrd.image"); handle_initrd(); return 1; } } sys_unlink("/initrd.image"); return 0; } 建立一个ROOT_RAM)的设备节点,并将/initrd/.image释放到这个节点中,/initrd.image的内容,就是我们之前分析的image-initrd。 如果根文件设备号不是ROOT_RAM0( 用户指定的根文件系统不是/dev/ram0就会转入到handle_initrd() 如果当前根文件系统是/dev/ram0.将其直接挂载就好了。 handle_initrd()代码如下: static void __init handle_initrd(void){ int error; int pid; real_root_dev = new_encode_dev(ROOT_DEV); create_dev("/dev/root.old", Root_RAM0); /* mount initrd on rootfs' /root */ mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); sys_mkdir("/old", 0700); root_fd = sys_open("/", 0, 0); old_fd = sys_open("/old", 0, 0); /* move initrd over / and chdir/chroot in initrd root */ sys_chdir("/root"); sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); /* * In case that a resume from disk is carried out by linuxrc or one of * its children, we need to tell the freezer not to wait for us. */ current->flags |= PF_FREEZER_SKIP; pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); if (pid > 0) while (pid != sys_wait4(-1, NULL, 0, NULL)) yield(); current->flags &= ~PF_FREEZER_SKIP; /* move initrd to rootfs' /old */ sys_fchdir(old_fd); sys_mount("/", ".", NULL, MS_MOVE, NULL); /* switch root and cwd back to / of rootfs */ sys_fchdir(root_fd); sys_chroot(".");

    sys_close(old_fd); sys_close(root_fd); if (new_decode_dev(real_root_dev) == Root_RAM0) { sys_chdir("/old"); return; } ROOT_DEV = new_decode_dev(real_root_dev); mount_root(); printk(KERN_NOTICE "Trying to move old root to /initrd ... "); error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL); if (!error) printk("okay/n"); else { int fd = sys_open("/dev/root.old", O_RDWR, 0); if (error == -ENOENT) printk("/initrd does not exist. Ignored./n"); else printk("failed/n"); printk(KERN_NOTICE "Unmounting old root/n"); sys_umount("/old", MNT_DETACH); printk(KERN_NOTICE "Trying to free ramdisk memory ... "); if (fd < 0) { error = fd; }else {

    error = sys_ioctl(fd, BLKFLSBUF, 0); sys_close(fd); } printk(!error ? "okay/n" : "failed/n"); } } 先将/dev/ram0挂载,而后执行/linuxrc.等其执行完后。切换根目录,再挂载具体的根文件系统. 到这里。文件系统挂载的全部内容就分析完了. 五:小结 在本小节里。分析了根文件系统的挂载流程。并对几个虚拟根文件系统的情况做了详细的分析。理解这部份,对我们构建linux嵌入式开发系统是很有帮助的. PS:参考资料:ibm技术论坛的<<Linux2.6 内核的 Initrd 机制解析>> 附根文件系统挂载流程图

     

    文章出处:飞诺网(www.firnow.com):http://dev.firnow.com/course/6_system/linux/Linuxjs/200888/135226.html

    展开全文
  • Table of Contents ...3.文件系统挂载vfsmount 4.超级块(struct super_bloc) 5.目录索引节点(struct inode): 5.目录项对象(struct dentry): 6.file 结构体 7. 打开的文件集 8.文件查找相关的数据结构...

    Table of Contents

     

    一、代码流程

    二、相关数据结构

    0.基本概念

    1.进程控制块PCB

    2.文件系统类型

    3.文件系统挂载vfsmount

    4.超级块(struct super_bloc)

    5.目录索引节点(struct inode):

    5.目录项对象(struct dentry):

    6.file 结构体

    7. 打开的文件集

    8.文件查找相关的数据结构

    三、注册/创建、安装/挂载rootfs

    1.向内核注册rootfs虚拟文件系统init_rootfs

    2.建立rootfs的根目录,并将rootfs挂载到自己的根目录


    一、代码流程

    在执行kernel_init之前,会建立roofs文件系统。(kernel_init启动用户空间的第一个进程init)

    根文件系统的挂载会经过如下步骤:

    1. [1*]处设置了根目录的名字为“/”。
    2. [2*]处设置了vfsmount中的root目录
    3. [3*]处设置了vfsmount中的超级块
    4. [4*]处设置了vfsmount中的文件挂载点,指向了自己
    5. [5*]处设置了vfsmount中的父文件系统的vfsmount为自己
    start_kernel
      vfs_caches_init
        mnt_init
          init_rootfs注册rootfs文件系统
          init_mount_tree 挂载rootfs文件系统
            vfs_kern_mount
              mount_fs
                type->mount其实是rootfs_mount 
                  mount_nodev
                    fill_super 其实是ramfs_fill_super
                      inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0);
                      sb->s_root = d_make_root(inode);
                        static const struct qstr name = QSTR_INIT("/", 1);[1*]
                        __d_alloc(root_inode->i_sb, &name);
              ...
              mnt->mnt.mnt_root = root;[2*]
              mnt->mnt.mnt_sb = root->d_sb;[3*]
              mnt->mnt_mountpoint = mnt->mnt.mnt_root;[4*]
              mnt->mnt_parent = mnt;[5*]
                     root.mnt = mnt;
            root.dentry = mnt->mnt_root;
            mnt->mnt_flags |= MNT_LOCKED;
            set_fs_pwd(current->fs, &root);
            set_fs_root(current->fs, &root);
      ...
      rest_init
        kernel_thread(kernel_init, NULL, CLONE_FS);

    二、相关数据结构

    0.基本概念

    从本质上讲,文件系统是特殊的数据分层存储结构,它包含文件、目录和相关的控制信息。为了描述 这个结构,Linux引入了一些基本概念:

    文件 一组在逻辑上具有完整意义的信息项的系列。在Linux中,除了普通文件,其他诸如目录、设备、套接字等 也以文件被对待。总之,“一切皆文件”。

    目录 目录好比一个文件夹,用来容纳相关文件。因为目录可以包含子目录,所以目录是可以层层嵌套,形成 文件路径。在Linux中,目录也是以一种特殊文件被对待的,所以用于文件的操作同样也可以用在目录上。

    目录项 在一个文件路径中,路径中的每一部分都被称为目录项;如路径/home/source/helloworld.c中,目录 /, home, source和文件 helloworld.c都是一个目录项。

    索引节点 用于存储文件的元数据的一个数据结构。文件的元数据,也就是文件的相关信息,和文件本身是两个不同 的概念。它包含的是诸如文件的大小、拥有者、创建时间、磁盘位置等和文件相关的信息。

    超级块 用于存储文件系统的控制信息的数据结构。描述文件系统的状态、文件系统类型、大小、区块数、索引节 点数等,存放于磁盘的特定扇区中。

    如上的几个概念在磁盘中的位置关系如图所示。

    1.进程控制块PCB

    struct task_struct {  
          ......  
          struct thread_info *thread_info;  
          struct list_head tasks;  
          pid_t pid;  
          pid_t tgid;  
          uid_t uid,euid,suid,fsuid;  
          gid_t gid,egid,sgid,fsgid;  
          struct fs_struct *fs;  //本节将大量使用这个  
          struct files_struct *files;  
          ......  
    }  
    

     

    struct fs_struct {
    	int users;
    	spinlock_t lock;
    	seqcount_t seq;
    	int umask;
    	int in_exec;
    	struct path root, pwd;
    };

    2.文件系统类型

    kernel/include/linux/fs.h

    struct file_system_type {
    	const char *name;
    	int fs_flags;
    #define FS_REQUIRES_DEV		1 
    #define FS_BINARY_MOUNTDATA	2
    #define FS_HAS_SUBTYPE		4
    #define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */
    #define FS_USERNS_DEV_MOUNT	16 /* A userns mount does not imply MNT_NODEV */
    #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move() during rename() internally. */
    	struct dentry *(*mount) (struct file_system_type *, int,
    		       const char *, void *);  //安装/挂载文件系统时,会调用;获取超级块。
    	void (*kill_sb) (struct super_block *);   //卸载文件系统时会调用。
    	struct module *owner;
    	struct file_system_type * next;      //指向下一个文件系统类型。
    	struct hlist_head fs_supers;      //同一个文件系统类型中所有超级块组成双向链表。 
    
    	struct lock_class_key s_lock_key;
    	struct lock_class_key s_umount_key;
    	struct lock_class_key s_vfs_rename_key;
    	struct lock_class_key s_writers_key[SB_FREEZE_LEVELS];
    
    	struct lock_class_key i_lock_key;
    	struct lock_class_key i_mutex_key;
    	struct lock_class_key i_mutex_dir_key;
    };

    3.文件系统挂载vfsmount

    本质上,mount操作的过程就是新建一个vfsmount结构,然后将此结构和挂载点(目录项对象)关联。关联之后,目录查找时就能沿着vfsmount挂载点一级级向下查找文件了。对于每一个mount的文件系统,都由一个vfsmount实例来表示。

    kernel/include/linux/mount.h

    
        struct vfsmount {  
          struct list_head mnt_hash; //内核通过哈希表对vfsmount进行管理  
          struct vfsmount *mnt_parent;  //指向父文件系统对应的vfsmount  
          struct dentry *mnt_mountpoint; //指向该文件系统挂载点对应的目录项对象dentry  
          struct dentry *mnt_root; //该文件系统对应的设备根目录dentry  
          struct super_block *mnt_sb; //指向该文件系统对应的超级块  
          struct list_head mnt_mounts;   
          struct list_head mnt_child;  //同一个父文件系统中的所有子文件系统通过该字段链接成双联表  
          int mnt_flags;  
          /* 4 bytes hole on 64bits arches */  
          const char *mnt_devname;  /* Name of device e.g. /dev/dsk/hda1 */  
          struct list_head mnt_list;  //所有已挂载文件系统的vfsmount结构通过该字段链接在一起  
          struct list_head mnt_expire;  /* link in fs-specific expiry list */  
          struct list_head mnt_share;   /* circular list of shared mounts */  
          struct list_head mnt_slave_list;/* list of slave mounts */  
          struct list_head mnt_slave;   /* slave list entry */  
          struct vfsmount *mnt_master;  /* slave is on master->mnt_slave_list */  
          struct mnt_namespace *mnt_ns; /* containing namespace */  
          int mnt_id;           /* mount identifier */  
          int mnt_group_id;     /* peer group identifier */  
          /* 
          * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount 
          * to let these frequently modified fields in a separate cache line 
          * (so that reads of mnt_flags wont ping-pong on SMP machines) 
          */  
          atomic_t mnt_count;  
          int mnt_expiry_mark;      /* true if marked for expiry */  
          int mnt_pinned;  
          int mnt_ghosts;  
          /* 
          * This value is not stable unless all of the mnt_writers[] spinlocks 
          * are held, and all mnt_writer[]s on this mount have 0 as their ->count 
          */  
          atomic_t __mnt_writers;  
        };  
    

    4.超级块(struct super_bloc)

    kernel/include/linux/fs.h

    struct super_block {
    	struct list_head	s_list;		/* 指向超级块链表的指针 */
    	dev_t			s_dev;		/* search index; _not_ kdev_t */
    	unsigned char		s_blocksize_bits;
    	unsigned long		s_blocksize;
    	loff_t			s_maxbytes;	/* Max file size */
    	struct file_system_type	*s_type;       //文件系统类型
    	const struct super_operations	*s_op;
    	const struct dquot_operations	*dq_op;
    	const struct quotactl_ops	*s_qcop;
    	const struct export_operations *s_export_op;
    	unsigned long		s_flags;
    	unsigned long		s_magic;
    	struct dentry		*s_root;
    	struct rw_semaphore	s_umount;
    	int			s_count;
    	atomic_t		s_active;
    #ifdef CONFIG_SECURITY
    	void                    *s_security;
    #endif
    	const struct xattr_handler **s_xattr;
    
    	struct list_head	s_inodes;	/* all inodes */
    	struct hlist_bl_head	s_anon;		/* anonymous dentries for (nfs) exporting */
    	struct list_head	s_mounts;	/* list of mounts; _not_ for fs use */
    	struct block_device	*s_bdev;
    	struct backing_dev_info *s_bdi;
    	struct mtd_info		*s_mtd;
    	struct hlist_node	s_instances;
    	struct quota_info	s_dquot;	/* Diskquota specific options */
    
    	struct sb_writers	s_writers;
    
    	char s_id[32];				/* Informational name */
    	u8 s_uuid[16];				/* UUID */
    
    	void 			*s_fs_info;	/* Filesystem private info */
    	unsigned int		s_max_links;
    	fmode_t			s_mode;
    
    	/* Granularity of c/m/atime in ns.
    	   Cannot be worse than a second */
    	u32		   s_time_gran;
    
    	/*
    	 * The next field is for VFS *only*. No filesystems have any business
    	 * even looking at it. You had been warned.
    	 */
    	struct mutex s_vfs_rename_mutex;	/* Kludge */
    
    	/*
    	 * Filesystem subtype.  If non-empty the filesystem type field
    	 * in /proc/mounts will be "type.subtype"
    	 */
    	char *s_subtype;
    
    	/*
    	 * Saved mount options for lazy filesystems using
    	 * generic_show_options()
    	 */
    	char __rcu *s_options;
    	const struct dentry_operations *s_d_op; /* default d_op for dentries */
    
    	/*
    	 * Saved pool identifier for cleancache (-1 means none)
    	 */
    	int cleancache_poolid;
    
    	struct shrinker s_shrink;	/* per-sb shrinker handle */
    
    	/* Number of inodes with nlink == 0 but still referenced */
    	atomic_long_t s_remove_count;
    
    	/* Being remounted read-only */
    	int s_readonly_remount;
    
    	/* AIO completions deferred from interrupt context */
    	struct workqueue_struct *s_dio_done_wq;
    	struct hlist_head s_pins;
    
    	/*
    	 * Keep the lru lists last in the structure so they always sit on their
    	 * own individual cachelines.
    	 */
    	struct list_lru		s_dentry_lru ____cacheline_aligned_in_smp;
    	struct list_lru		s_inode_lru ____cacheline_aligned_in_smp;
    	struct rcu_head		rcu;
    
    	/*
    	 * Indicates how deep in a filesystem stack this SB is
    	 */
    	int s_stack_depth;
    };

    5.目录索引节点(struct inode):

    文件数据都储存在"块"中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为"索引节点"。

    kernel/include/linux/fs.h

    
        struct inode {  
          struct hlist_node i_hash; //哈希表节点  
          struct list_head  i_list;  
          struct list_head  i_sb_list;  
          struct list_head  i_dentry;  
          unsigned long     i_ino;  
          atomic_t      i_count;  
          unsigned int      i_nlink;  
          uid_t         i_uid;     //文件所有者
          gid_t         i_gid;      //文件所有者所属的用户组
          dev_t         i_rdev;  
          u64           i_version;  
          loff_t            i_size;  
        #ifdef __NEED_I_SIZE_ORDERED  
          seqcount_t        i_size_seqcount;  
        #endif  
          struct timespec       i_atime;  
          struct timespec       i_mtime;  //修改时间
          struct timespec       i_ctime;  //创建时间
          unsigned int      i_blkbits;  
          blkcnt_t      i_blocks;  
          unsigned short          i_bytes;  
          umode_t           i_mode;         //文件的读写权限
          spinlock_t        i_lock; /* i_blocks, i_bytes, maybe i_size */  
          struct mutex      i_mutex;  
          struct rw_semaphore   i_alloc_sem;  
          const struct inode_operations *i_op;  
          const struct file_operations  *i_fop; /* former ->i_op->default_file_ops */  
          struct super_block    *i_sb;  
          struct file_lock  *i_flock;  
          struct address_space  *i_mapping;  
          struct address_space  i_data;  
        #ifdef CONFIG_QUOTA  
          struct dquot      *i_dquot[MAXQUOTAS];  
        #endif  
          struct list_head  i_devices;  
          union {  
            struct pipe_inode_info  *i_pipe;  
            struct block_device *i_bdev;  
            struct cdev     *i_cdev;  
          };  
          int           i_cindex;  
          
          __u32         i_generation;  
          
        #ifdef CONFIG_DNOTIFY  
          unsigned long     i_dnotify_mask; /* Directory notify events */  
          struct dnotify_struct *i_dnotify; /* for directory notifications */  
        #endif  
          
        #ifdef CONFIG_INOTIFY  
          struct list_head  inotify_watches; /* watches on this inode */  
          struct mutex      inotify_mutex;  /* protects the watches list */  
        #endif  
          
          unsigned long     i_state;  
          unsigned long     dirtied_when;   /* jiffies of first dirtying */  
          
          unsigned int      i_flags;  
          
          atomic_t      i_writecount;  
        #ifdef CONFIG_SECURITY  
          void          *i_security;  
        #endif  
          void          *i_private; /* fs or device private pointer */  
        };  
    

    5.目录项对象(struct dentry):

    dentry的中文名称是目录项,是Linux文件系统中某个索引节点(inode)的链接。这个索引节点可以是文件,也可以是目录。

    inode(可理解为ext2 inode)对应于物理磁盘上的具体对象,dentry是一个内存实体,其中的d_inode成员指向对应的inode。也就是说,一个inode可以在运行的时候链接多个dentry,而d_count记录了这个链接的数量。

    kernel/include/linux/dcache.h

    
        struct dentry {  
          atomic_t d_count;     //一个inode可以在运行的时候链接多个dentry,而d_count记录了这个链接的数量
          unsigned int d_flags;     /* protected by d_lock */  
          spinlock_t d_lock;        /* per dentry lock */  
          int d_mounted;  
          struct inode *d_inode; //目录项对象与目录索引的关联          
          /* Where the name belongs to - NULL is 
          * negative */  
          /* 
          * The next three fields are touched by __d_lookup.  Place them here 
          * so they all fit in a cache line. 
          */  
          struct hlist_node d_hash; //哈希表节点 /* lookup hash list */  
          struct dentry *d_parent; //目录项对象的父亲   /* parent directory */  
          struct qstr d_name; //d_name.name这个是文件名,目录对象与目录名的关联  
          
          struct list_head d_lru;       /* LRU list */  
          /* 
          * d_child and d_rcu can share memory 
          */  
          union {  
            struct list_head d_child;   /* child of parent list */  
            struct rcu_head d_rcu;  
          } d_u;  
          struct list_head d_subdirs;   /* our children */  
          struct list_head d_alias; /* inode alias list */  
          unsigned long d_time;     /* used by d_revalidate */  
          struct dentry_operations *d_op;  
          struct super_block *d_sb; //指向文件系统的超级块/* The root of the dentry tree */  
          void *d_fsdata;           /* fs-specific data */  
          
          unsigned char d_iname[DNAME_INLINE_LEN_MIN];  /* small names */  
        };  
    

    6.file 结构体

    struct file(file结构体):
      struct file结构体定义在include/linux/fs.h中定义。文件结构体代表一个打开的文件,系统中的每个打开的文件在内核空间都有一个关联的 struct file。

    
        struct file {  
          /* 
          * fu_list becomes invalid after file_free is called and queued via 
          * fu_rcuhead for RCU freeing 
          */  
          union {  
            struct list_head    fu_list;  
            struct rcu_head     fu_rcuhead;  
          } f_u;  
          struct path       f_path;  //重要!!!记录挂载信息和目录项信息  
        #define f_dentry    f_path.dentry  
        #define f_vfsmnt    f_path.mnt  
          const struct file_operations  *f_op;  
          atomic_long_t     f_count;  
          unsigned int      f_flags;  
          fmode_t           f_mode;  
          loff_t            f_pos;  
          struct fown_struct    f_owner;  
          const struct cred *f_cred;  
          struct file_ra_state  f_ra;  
          
          u64           f_version;  
        #ifdef CONFIG_SECURITY  
          void          *f_security;  
        #endif  
          /* needed for tty driver, and maybe others */  
          void          *private_data;  
          
        #ifdef CONFIG_EPOLL  
          /* Used by fs/eventpoll.c to link all the hooks to this file */  
          struct list_head  f_ep_links;  
          spinlock_t        f_ep_lock;  
        #endif /* #ifdef CONFIG_EPOLL */  
          struct address_space  *f_mapping;  
        #ifdef CONFIG_DEBUG_WRITECOUNT  
          unsigned long f_mnt_write_state;  
        #endif  
        };  
    

    每个进程在PCB(Process Control Block)即进程控制块中都保存着一份文件描述符表,文件描述符就是这个表的索引,文件描述表中每个表项都有一个指

    向已打开文件的指针,现在我们明确一下:已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体。

    我们在进程中打开一个文件F,实际上就是要在内存中建立F的dentry,和inode结构,并让它们与进程结构联系来,把VFS中定义的接口给接起来。我们来看一看这个经典的图:

    file结构体详解

    7. 打开的文件集

    struct files_struct {//打开的文件集
             atomic_t count;              /*结构的使用计数*/
            ……
             int max_fds;                 /*文件对象数的上限*/
            int max_fdset;               /*文件描述符的上限*/
            int next_fd;                 /*下一个文件描述符*/
            struct file ** fd;           /*全部文件对象数组*/
            ……
     };
    
    struct fs_struct {//建立进程与文件系统的关系
             atomic_t count;              /*结构的使用计数*/
            rwlock_t lock;               /*保护该结构体的锁*/
            int umask;                  /*默认的文件访问权限*/
            struct dentry * root;        /*根目录的目录项对象*/
            struct dentry * pwd;         /*当前工作目录的目录项对象*/
            struct dentry * altroot;    /*可供选择的根目录的目录项对象*/
            struct vfsmount * rootmnt;   /*根目录的安装点对象*/
            struct vfsmount * pwdmnt;    /*pwd的安装点对象*/
            struct vfsmount * altrootmnt;/*可供选择的根目录的安装点对象*/
    };

    回顾上节的图片很容易理解这两个数据结构

    8.文件查找相关的数据结构

    include/linux/fs_struct.h

    
        struct fs_struct {  
          atomic_t count;  
          rwlock_t lock;  
          int umask;  
          struct path root, pwd; //重要!!!记录挂载信息和目录项信息  
        };  
    

    include/linux/namei.h

    
        struct nameidata {  
          struct path   path;  //重要!!!记录挂载信息和目录项信息  
          struct qstr   last;  //重要!!!记录目录名  
          unsigned int  flags;  
          int       last_type;  
          unsigned  depth;  
          char *saved_names[MAX_NESTED_LINKS + 1];  
          
          /* Intent data */  
          union {  
            struct open_intent open;  
          } intent;  
        };  
    

    include/linux/path.h

    
        struct path {  
          struct vfsmount *mnt; //重要!!!记录文件系统挂载信息  
          struct dentry *dentry;  //重要!!!记录目录项信息  
        };  
    
    

    include/linux/dcache.h

     struct qstr {  
      unsigned int hash;  
      unsigned int len;  
      const unsigned char *name;//重要!!!目录/文件名字,如"/","tank1"等具体的文件名  
    }; 

    三、注册/创建、安装/挂载rootfs

    第一步:建立rootfs文件系统;

    第二步:调用其get_sb函数(对于rootfs这种内存/伪文件系统是get_sb_nodev,实际文件系统比如ext2等是get_sb_bdev)、建立超级块(包含目录项和i节点);

    第三步:挂载该文件系统(该文件系统的挂载点指向该文件系统超级块的根目录项);

    第四步:将系统current的根文件系统和根目录设置为rootfs和其根目录。

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

    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)  
    {  
      init_rootfs(); //向内核注册rootfs  
      init_mount_tree();//重要!!!rootfs根目录的建立以及rootfs文件系统的挂载;设置系统current根目录和根文件系统为rootfs  
    } 

    1.向内核注册rootfs虚拟文件系统init_rootfs

    kernel/fs/ramfs/inode.c

    
        int __init init_rootfs(void)  
        {  
          err = register_filesystem(&rootfs_fs_type);  
        }  
        static struct file_system_type rootfs_fs_type = {  
          .name     = "rootfs",  
          .get_sb       = rootfs_get_sb,  
          .kill_sb  = kill_litter_super,  
        };  
    

    2.建立rootfs的根目录,并将rootfs挂载到自己的根目录

    kernel/fs/namespace.c


    
        static void __init init_mount_tree(void)  
        {  
          struct vfsmount *mnt;  
          struct mnt_namespace *ns;  
          struct path root;  
          //创建rootfs的vfsmount结构,建立rootfs的超级块、并将rootfs挂载到自己的根目录。  
          /* 
          mnt->mnt_mountpoint = mnt->mnt_root = dget(sb->s_root),而该mnt和自己的sb是关联的; 
          所以,是把rootfs文件系统挂载到了自己对应的超级块的根目录上。 
          这里也是实现的关键:一般文件系统的挂载是调用do_mount->do_new_mount而该函数中首先调用do_kern_mount,这时mnt->mnt_mountpoint = mnt->mnt_root;但后边 
          它还会调用do_add_mount->graft_tree->attach_recursive_mnt如下代码mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt)改变了其挂载点!!! 
          */  
          mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);  
          list_add(&mnt->mnt_list, &ns->list);  
          ns->root = mnt; //将创建好的mnt加入系统当前  
          mnt->mnt_ns = ns;  
          
          init_task.nsproxy->mnt_ns = ns; //设置进程的命名空间  
          get_mnt_ns(ns);  
          
          root.mnt = ns->root; //文件系统为rootfs,相当与root.mnt = mnt;  
          root.dentry = ns->root->mnt_root;//目录项为根目录项,相当与root.dentry = mnt->mnt_root;  
          
          //设置系统current的pwd目录和文件系统  
          set_fs_pwd(current->fs, &root);  
          //设置系统current根目录,根文件系统。这个是关键!!!整个内核代码最多只有两处调用  
          set_fs_root(current->fs, &root);    
        }  
    
    

     

    展开全文
  • https://blog.csdn.net/guopeixin/article/details/5962482 initrd和initramfs的区别 ... linux启动分析之initramfs https://blog.csdn.net/BOJUE01/article/d...
    展开全文
  • Linux 中将一个文件系统与一个存储设备关联起来的过程称为挂载(mount)。使用 mount 命令将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂载时,要提供文件系统类型、文件系统和一个挂装点。根文件...

    本文旨在查找相关资料的基础上梳理一下老师上课的内容,巩固学习。

    一、定义概述

    挂载

    在 Linux 中将一个文件系统与一个存储设备关联起来的过程称为挂载(mount)。使用 mount 命令将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂载时,要提供文件系统类型、文件系统和一个挂装点。根文件系统被挂载到根目录下“/”上后,在根目录下就有根文件系统的各个目录,文件:/bin /sbin /mnt等,再将其他分区挂接到/mnt目录上,/mnt目录下就有这个分区的各个目录及文件。

    根文件系统

    根文件系统是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,而且是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导启动程序会在根文件系统挂载之后从中把一些初始化脚本和服务加载到内存中去运行。注:Linux中文件系统和内核是完全独立的两个部分。

    根文件系统常用目录

    • /bin目录

    该目录下的命令可以被root与一般账号所使用,由于这些命令在挂接其它文件系统之前就可以使用,所以/bin目录必须和根文件系统在同一个分区中。

    • /sbin 目录

    该目录下存放只有系统管理员能够使用的命令,系统命令还可以存放在/usr/sbin,/usr/local/sbin目录下,/sbin目录中存放的是基本的系统命令,它们用于启动系统和修复系统等,与/bin目录相似,在挂接其他文件系统之前就可以使用/sbin,所以/sbin目录必须和根文件系统在同一个分区中。

    • /dev目录

    该目录下存放的是设备与设备接口的文件,设备文件是Linux中特有的文件类型,在Linux系统下,以文件的方式访问各种设备,即通过读写某个设备文件操作某个具体硬件。例如通过"dev/ttySAC0"文件可以操作串口0。

    • /etc目录

    该目录下存放着系统主要的配置文件,例如人员的账号密码文件、各种服务的其实文件等。一般来说,此目录的各文件属性是可以让一般用户查阅的,但是只有root有权限修改。

    • /lib目录

    该目录下存放共享库和可加载驱动程序,共享库用于启动系统。运行根文件系统中的可执行程序,比如:/bin /sbin 目录下的程序。

    • /mnt目录

    用于临时挂载某个文件系统的挂接点,通常是空目录,也可以在里面创建一引起空的子目录,比如/mnt/cdram /mnt/hda1 。用来临时挂载光盘、移动存储设备等。

    •  /tmp目录

    用于存放临时文件,通常是空目录,一些需要生成临时文件的程序用到的/tmp目录下,所以/tmp目录必须存在并可以访问

    VFS

    VFS(virtual File System)是一个为各类文件系统提供了一个统一的操作界面和应用编程的接口。它可以让open()、read()、write()等系统调用不用关心底层的存储介质和文件系统类型就可以工作的层。

    二、根文件系统挂载过程

    嵌入式Linux系统执行流程

    BootLoader(引导加载程序)是在操作系统内核运行之前运行。在嵌入式系统中,通常并没有像BIOS那样的固件程序,因此整个系统的加载启动任务就完全由BootLoader来完成,它主要用来初始化处理器及外设,然后调用Linux内核。Linux内核在完成系统的初始化之后需要挂载根文件系统,然后加载必要的内核模块,启动应用程序。这就是嵌入式Linux系统启动过程Linux引导的整个过程。

    根文件系统挂载

    总体概括

    1.  内核挂载一个虚拟的rootfs作为初始文件系统 这一步的作用主要是形成一个根文件系统挂载点./
    2. 第二步: 挂载文件系统rootfs作为初始文件系统 这里的rootfs和上面有所区别(上面主要是提供挂载点和进程命名空间) 常见rootfs :initramfs:在内核镜像中包含cpio包,在内核启动时被解开,释放到rootfs ,cpio-initrd: cpio格式的rootfs; image-initrd: 传统格式的rootfs
    3. 第三步: 挂载一个真正的根文件系统替换rootfs;当然这一步不一定存在。 上面的rootfs也可以直接作为最终的文件系统

    接下来详细分析上述过程。 

    • 准备一个虚拟的文件系统rootfs,并把它初始为根文件系统。其目的是形成一个根文件系统挂载点。

    函数调用顺序

    start_kernel()->vfs_caches_init() ->mnt_init()

    mnt_init()挂载了一个空的rootfs文件系统,并把它的根目录作为内核当前进程的根目录,从而使得这个rootfs的根目录就是./。注:此时是虚拟的rootfs,后面还会指向具体的根文件系统。

    mnt_init()源代码如下:

    void __init mnt_init(void)  
    {  
      ...........
      init_rootfs(); //向内核注册rootfs  
      init_mount_tree();//rootfs文件系统的挂载;设置系统current根目录和根文件系统为rootfs,  也就是./挂载点的形成
    }  

      2.initrd

    intrid 的常见两种格式处理流程

     

    •  InitRamfs(cpio-initrd),使用根文件系统下的/init来作为init进程 
    •  InitRamdisk(image-initrd),使用根文件系统下的/linuxrc来作为init进程

    populate_rootfs函数负责加载initramfs(cpio-initrd) 到根文件系统rootfs,若不是将其释放到/initrd.image.。注:rootfs_initcall(populate_rootfs)

     

    尝试访问ramdisk_execute_command,默认为/init,如果访问失败,说明根目录上不存在这个文件,则调用prepare_namespace() 。对于initramdisk(image-initrd)和cpio-initrd的情况,都会将虚拟根文件系统释放到根目录。

    • 如果这些虚拟文件系统里有/init这个文件。就会转入到init_post()。
    • 对于image-initrd或者是虚拟文件系统中没有包含 /init的情况,会由prepare_namespace()处理。

    prepare_namespace()解释。用户可以用root=来指定根文件系统,它的值保存在saved_root_name中。

    • 如果用户指定了以mtd(内存技术设备)开始的字串做为它的根文件系统。就会直接去挂载。这个文件是mtdblock的设备文件。
    • 如果指定的根文件系统是 initrd其本身,直接挂载为根文件系统
    • 如果不是进一步处理:调用initrd_load() 

     initrd_load() 函数解释

    • 建立一个(ROOT_RAM)的设备节点,并将/initrd/.image释放到这个节点中,/initrd.image的内容,就是我们之前分析的image-initrd。
    • 如果根文件设备号不是ROOT_RAM0( 用户指定的根文件系统不是/dev/ram0就会转入到handle_initrd()
    • 如果当前根文件系统是/dev/ram0. 直接退出。

     handle_initrd()先将/dev/ram0挂载,而后执行/linuxrc.等其执行完后,再挂载具体的根文件系统.。

     

     

     

    展开全文
  • 对linux系统而言,对一个文件系统,如果想要使用它,就必须对其进行挂载挂载就是将文件系统安装到linux文件系统的某个目录下,这个目录可以自己创建,或则选择linux存在的目录,必须是目录文件就行了,挂载后,这...
  • 文章目录1. mount系统调用1.1.... 挂载文件系统2.1. init_rootfs2.2. init_mount_tree3. 参考资料 1. mount系统调用 1.1. sys_mount sys_mount主要将系统调用的参数dev_name、dir_name、type、flags、d...
  • 嵌入式Linux系统由三部分组成: uboot、kernel、根文件系统, 还是这张老图 这里的根文件系统可以说是包含两个部分: 一个是根,一个是文件系统 那么什么是根呢?哈哈 其实根表示的就是第一个的意思 下面贴...
  • Linux 创建文件系统挂载文件系统流程详解 原地址:http://www.linuxsir.org/main/?q=node/83 作者:北南南北 来自: LinuxSir.Org 摘要:本文对新增硬盘,切割硬盘,创建硬盘分区,为硬盘分区创建文件系统,以及...
  • Linux文件系统详解

    2019-05-29 16:07:53
    从操作系统的角度详解Linux文件系统层次、文件系统分类、文件系统的存储结构、不同存储介质的区别(RAM、ROM、Flash)、存储节点inode。本文参考: http://blog.chinaunix.net/uid-8698570-id-1763151.html ...
  • Linux文件系统的制作什么是文件系统计算机的文件系统是一种存储和组织计算机数据的方法,它使得对其访问和查找变得容易,文件系统使用文件和树形目录的抽象逻辑概念代替了硬盘和光盘等物理设备使用数据块的概念,...
  • 前言: 本篇文章以S3C6410公版的Linux BSP和U-Boot来进行分析,文中所有提及的名词和数据都是以该环境为例,所有的代码流程也是以该环境为例来进行分析。哈哈。如果有不正确或者不完善的地方,欢迎前来拍砖留言或者...
  • 1.数据结构 ...下面将对文件系统挂载过程中涉及到的两个主要数据结构vfsmount和path进行节本说明。...每个挂载在内核目录树中的文件系统都将对应一个vfsmount结构,下面将对该结构中的部分字段进行说明
  • 在了解启动流程之前,我们应该先知道系统的几个重要脚本和配置文件,他们对应的路径为: 1. /sbin/init 2. /etc/inittab 3. /etc/rc.d/rc.sysinit 4. /etc/rc.d/rcN.d //这是几个文件夹N代表数字1,2,3,4.. 5. /etc/...
  • 前边通过源码情景分析,看过了总线、设备、驱动及其发现机制,Linux2.6内核udev设备节点创建相关;...下边将根文件系统挂载过程做简单分析: 一、rootfs的诞生 引子: Linux一切皆文件的提出:在Linux中,
  • 初学者,请高人指教! 首先,手动挂载: 1、查看设备及硬盘分区情况:fdisk -l 2、给想要挂载的硬盘(假设我新添加的设备dev/sda)分区:... 3、创建文件系统:  mkfs.ext3 /dev/sda1 或者 mkfs -t ext3
  • 1.根文件系统挂载 mount_root[init/do_mounts.c] create_dev(“/dev/root”, ROOT_DEV) ==> how to do this sys_unlink(“/dev/root”) sys_mknod(“/dev/root”,…) mount_block_root(“/dev/root”, flags) ...
  • 因此在介绍该文件系统的同时,也需要说明linux的设备驱动程序模型。 本次sysfs文件系统分析主要涉及如下几个主题: 一、sysfs文件系统注册以及挂载 文件系统的注册; 文件系统挂载 二、sysfs文件系统相关...
  • Linux 虚拟文件系统二MountOpen设备文件挂载和打开文件 梗概 挂载 设备文件 设备文件从哪里来的 挂载做了什么 打开文件 打开文件和挂载的巧妙结合 打开文件实际情况 请结合Linux内核情景分析 声明 ...
1 2 3 4 5 ... 20
收藏数 24,623
精华内容 9,849
关键字:

linux文件系统挂载流程