一、initrd介绍

对于使用initramfs镜像的ramdisk来说,这个rootfs即为ramfs(ram file system),它是一个在解压initramfs镜像后就存在且挂载的文件系统,但是系统启动之后用户并不能找到它,因为在内核启动完成后它就会被切换到真实的根文件系统。
前文也提到过,在systemd眼中,initramfs构建的也是一个系统,只不过是虚拟系统,最终systemd会从这个虚拟系统中切换到真实的系统中,切换的内容主要包括两项:切换根分区,切换systemd进程自身。
initrd的具体实现过程是这样的:bootloader把根文件系统映象装载到内存指定位置,把相关参数传递给内核,内核启动时把initrd中的内容复制到ramdisk中(ram0),把initrd占用的内存释放掉,在ram0上mount根文件系统initrd = init ramdisk,是一个启动时存在于内存的文件系统。

二、initrd启动流程

使用initrd的时候,典型的系统启动的流程变为:
1) Boot Loader读入内核镜像以及initrd文件
2) 内核将initrd文件转成“普通”的RAM盘,并且释放掉initrd文件占用的内存。
3) initrd被当作root文件系统,以可读可写(read-write)方式安装。
4) /linuxrc被执行(它可以是任何可执行文件,包括脚本在内;它以uid0身份执行,基本上能完成所有init程序可以做的工作)
5) linuxrc安装“实际”的root文件系统
6) linuxrc通过pivot_root系统调用将root文件系统放置在root目录下。
7) 常用的启动流程(比如调用/sbin/init)开始执行。
8) 卸载initrd文件系统。
注意,这是一个典型流程。其实initrd机制可以通过两种方式使用:要么就是作为一个普通的root文件系统使用,这样的话第5、第6两个步骤可以被略过,直接执行/sbin/init(我们的试验系统就是利用这种方法);要么作为一个过渡环境使用,通过它内核可以继续装载“实际”的root文件系统。

三、initrd启动代码基本过程

加载Linux Kernel和Rootfs加载到内存,并跳转到Linux Kernel入口地址执行程序。
start_kernel入口——init/main.c: asmlinkage __visible void __init start_kernel(void)
fs/dcache.c: vfs_caches_init();
fs/namespace.c:void __init mnt_init(void)
init/do_mounts.c:int __init init_rootfs(void)
fs/namespace.c:static void __init init_mount_tree(void)
fs/namespace.c:vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
fs/super.c:mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
mount_nodev: mount a filesystem that is not backed by a device

//解压initramfs文件系统中的内容到rootfs
init/main.c:void __init __weak arch_call_rest_init(void)——rest_init();——启动idel进行(pid=0,运行在内核态);启动kernel_init进程(init进程通过kernel_thread创建,在内核完成初始化后,加载init程序);启动kthreadd进程(由idle通过kernel_thread创建,并运行在内核空间,负责所有的内核线程的调度和管理)
init/main.c kernel_thread(kernel_init, NULL, CLONE_FS);
init/main.c tatic noinline void __init kernel_init_freeable(void)
static void __init do_basic_setup(void)
static void __init do_initcalls(void)
init/noinitramfs.c:rootfs_initcall(default_rootfs)
注:此时rootfs还没有挂载,现在的根目录是ramfs
init/do_mounts.c: void __init prepare_namespace(void)
init/do_mounts.c: void __init mount_block_root(char *name, int flags)
init/do_mounts.c: static int __init do_mount_root(char *name, char *fs, int flags, void *data)
void __init mount_root(void)

四、initrd启动详细代码分析

void __init vfs_caches_init(void){names_cachep = kmem_cache_create_usercopy("names_cache", PATH_MAX, 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, 0, PATH_MAX, NULL);dcache_init();//页目录缓存的初始化inode_init();//索引节点缓存的初始化files_init();//文件初始化files_maxfiles_init();mnt_init();//最重要的函数,虚拟文件系统挂载的初始化,创建一个rootfs,这是一个虚拟的rootfs,即内存文件系统,后面才会执行真实文件系统bdev_cache_init();//块设备初始化chrdev_init();//字符设备初始化}void __init mnt_init(void)
{int err;mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount),0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);mount_hashtable = alloc_large_system_hash("Mount-cache",sizeof(struct hlist_head),mhash_entries, 19,HASH_ZERO,&m_hash_shift, &m_hash_mask, 0, 0);mountpoint_hashtable = alloc_large_system_hash("Mountpoint-cache",sizeof(struct hlist_head),mphash_entries, 19,HASH_ZERO,&mp_hash_shift, &mp_hash_mask, 0, 0);if (!mount_hashtable || !mountpoint_hashtable)panic("Failed to allocate mount hash table\n");kernfs_init();  //RCU context,申请kmem_cache_create("kernfs_node_cache"资源err = sysfs_init();//sysfs 初始化if (err)printk(KERN_WARNING "%s: sysfs_init error: %d\n",__func__, err);fs_kobj = kobject_create_and_add("fs", NULL);//生成名为fs的kobject对象fs_kobjif (!fs_kobj)printk(KERN_WARNING "%s: kobj create error\n", __func__);init_rootfs();//初始化rootfs文件系统init_mount_tree();//初始化mount树。挂载rootfs文件系统
}int __init init_rootfs(void){int err = register_filesystem(&rootfs_fs_type); //注册rootfs文件系统if (err)return err;if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] &&(!root_fs_names || strstr(root_fs_names, "tmpfs"))) {err = shmem_init();is_tmpfs = true;} else {err = init_ramfs_fs();}if (err)unregister_filesystem(&rootfs_fs_type);//失败后,卸载文件系统return err;}static struct file_system_type rootfs_fs_type = {.name       = "rootfs",.mount      = rootfs_mount,.kill_sb    = kill_litter_super,};static void __init init_mount_tree(void){struct vfsmount *mnt;//挂载点struct mnt_namespace *ns;//命名空间struct path root;//根路径struct file_system_type *type;//类型type = get_fs_type("rootfs");if (!type)panic("Can't find rootfs type");mnt = vfs_kern_mount(type, 0, "rootfs", NULL);//挂载rootfs文件系统,返回挂载点put_filesystem(type);if (IS_ERR(mnt))panic("Can't create rootfs");ns = create_mnt_ns(mnt);//为命名空间分配空间if (IS_ERR(ns))panic("Can't allocate initial namespace");init_task.nsproxy->mnt_ns = ns;//第一个进程的命名空间进行初始化get_mnt_ns(ns);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);设置/目录为根目录}struct vfsmount *vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data){struct mount *mnt;struct dentry *root;if (!type)return ERR_PTR(-ENODEV);mnt = alloc_vfsmnt(name);//分配一个新的已安装文件系统的描述符,存放在局部变量mnt中if (!mnt)return ERR_PTR(-ENOMEM);if (flags & SB_KERNMOUNT)mnt->mnt.mnt_flags = MNT_INTERNAL;root = mount_fs(type, flags, name, data);//挂载rootfs文件系统if (IS_ERR(root)) {mnt_free_id(mnt);free_vfsmnt(mnt);return ERR_CAST(root);}mnt->mnt.mnt_root = root;//挂载点主目录指向根目录mnt->mnt.mnt_sb = root->d_sb;mnt->mnt_mountpoint = mnt->mnt.mnt_root;//挂载点根目录指向与文件系统根目录对应的目录项对象的地址mnt->mnt_parent = mnt;//挂载点父目录指向自己lock_mount_hash();list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);unlock_mount_hash();return &mnt->mnt;//返回挂载点}EXPORT_SYMBOL_GPL(vfs_kern_mount);struct dentry *
mount_fs(struct file_system_type *type, int flags, const char *name, void *data){struct dentry *root;struct super_block *sb;int error = -ENOMEM;void *sec_opts = NULL;if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {error = security_sb_eat_lsm_opts(data, &sec_opts);if (error)return ERR_PTR(error);}root = type->mount(type, flags, name, data);//回调函数,目的是在每个文件系统类型注册到内核中实现的一个mount函数,为了完成针对特定文件系统特点操作而个别实现的回调函数rootfs_mountif (IS_ERR(root)) {error = PTR_ERR(root);goto out_free_secdata;}sb = root->d_sb;BUG_ON(!sb);WARN_ON(!sb->s_bdi);/** Write barrier is for super_cache_count(). We place it before setting* SB_BORN as the data dependency between the two functions is the* superblock structure contents that we just set up, not the SB_BORN* flag.*/smp_wmb();sb->s_flags |= SB_BORN;error = security_sb_set_mnt_opts(sb, sec_opts, 0, NULL);if (error)goto out_sb;if (!(flags & (MS_KERNMOUNT|MS_SUBMOUNT))) {error = security_sb_kern_mount(sb);if (error)goto out_sb;}/** filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE* but s_maxbytes was an unsigned long long for many releases. Throw* this warning for a little while to try and catch filesystems that* violate this rule.*/WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to ""negative value (%lld)\n", type->name, sb->s_maxbytes);up_write(&sb->s_umount);security_free_mnt_opts(&sec_opts);return root;out_sb:dput(root);deactivate_locked_super(sb);out_free_secdata:security_free_mnt_opts(&sec_opts);return ERR_PTR(error);
}noinline void __ref rest_init(void){struct task_struct *tsk;int pid;rcu_scheduler_starting();/** We need to spawn init first so that it obtains pid 1, however* the init task will end up wanting to create kthreads, which, if* we schedule it before we create kthreadd, will OOPS.*/pid = kernel_thread(kernel_init, NULL, CLONE_FS);//创建系统中的第一个进程Kernel_Init/** Pin init on the boot CPU. Task migration is not properly working* until sched_init_smp() has been run. It will set the allowed* CPUs for init to the non isolated CPUs.*/rcu_read_lock();tsk = find_task_by_pid_ns(pid, &init_pid_ns);set_cpus_allowed_ptr(tsk, cpumask_of(smp_processor_id()));rcu_read_unlock();numa_default_policy();pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);rcu_read_lock();kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);rcu_read_unlock();/** Enable might_sleep() and smp_processor_id() checks.* They cannot be enabled earlier because with CONFIG_PREEMPT=y* kernel_thread() would trigger might_sleep() splats. With* CONFIG_PREEMPT_VOLUNTARY=y the init task might have scheduled* already, but it's stuck on the kthreadd_done completion.*/system_state = SYSTEM_SCHEDULING;complete(&kthreadd_done);/** The boot idle thread must execute schedule()* at least once to get things moving:*/schedule_preempt_disabled();/* Call into cpu_idle with preempt disabled */cpu_startup_entry(CPUHP_ONLINE);}static int __ref kernel_init(void *unused){int ret;kernel_init_freeable();//主要执行的,initrd文件系统内容到rootfs/* need to finish all async __init code before freeing the memory */async_synchronize_full();ftrace_free_init_mem();free_initmem();//释放内存mark_readonly();/** Kernel mappings are now finalized - update the userspace page-table* to finalize PTI.*/pti_finalize();system_state = SYSTEM_RUNNING;numa_default_policy();rcu_end_inkernel_boot();if (ramdisk_execute_command) {ret = run_init_process(ramdisk_execute_command);if (!ret)return 0;pr_err("Failed to execute %s (error %d)\n",ramdisk_execute_command, ret);}/** 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) {ret = run_init_process(execute_command);if (!ret)return 0;panic("Requested init %s failed (error %d).",execute_command, ret);}if (!try_to_run_init_process("/sbin/init") ||!try_to_run_init_process("/etc/init") ||!try_to_run_init_process("/bin/init") ||!try_to_run_init_process("/bin/sh"))  //文件系统搜寻可执行文件,
执行/sbin/init程序,这个程序存在于根文件系统,如果存在,执行它,系统的控制权交给/sbin/init,不再返回init_post函数return 0;panic("No working init found.  Try passing init= option to kernel. ""See Linux Documentation/admin-guide/init.rst for guidance.");}static noinline void __init kernel_init_freeable(void){/** Wait until kthreadd is all set-up.*/wait_for_completion(&kthreadd_done);/* Now the scheduler is fully set up and can do blocking allocations */gfp_allowed_mask = __GFP_BITS_MASK;/** init can allocate pages on any node*/set_mems_allowed(node_states[N_MEMORY]);cad_pid = task_pid(current);smp_prepare_cpus(setup_max_cpus);workqueue_init();init_mm_internals();do_pre_smp_initcalls();lockup_detector_init();smp_init();sched_init_smp();page_alloc_init_late();/* Initialize page ext after all struct pages are initialized. */page_ext_init();//页缓存初始化do_basic_setup();//调用所有模块的初始化函数,加载rootfs到内存/* Open the /dev/console on the rootfs, this should never fail */if (ksys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)//打开/dev/console(位于rootfs中)pr_err("Warning: unable to open an initial console.\n");(void) ksys_dup(0);(void) ksys_dup(0);/** check if there is an early userspace init.  If yes, let it do all* the work*/if (!ramdisk_execute_command)ramdisk_execute_command = "/init";//执行/init,其实就是解压里存在/init后,就用这个挂载真正的文件系统if (ksys_access((const char __user *)ramdisk_execute_command, 0) != 0) {ramdisk_execute_command = NULL;prepare_namespace();//如果不存在/init,则执行propare_namespace挂载文件系统,为进程0准备命名空间}/** 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..** rootfs is available now, try loading the public keys* and default modules*/integrity_load_keys();//若存在则执行integrity_load_keys,进行真正的根文件系统的init进程进行,已经到实际文件系统,加载默认模块}/** Ok, the machine is now initialized. None of the devices* have been touched yet, but the CPU subsystem is up and* running, and memory and process management works.** Now we can finally start doing some real work..*/
//进行各模块初始化static void __init do_basic_setup(void){cpuset_init_smp();shmem_init();driver_init();init_irq_proc();do_ctors();usermodehelper_enable();do_initcalls();}static void __init do_initcalls(void){int level;for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)do_initcall_level(level);//包括执行roofs_initcall}#define pure_initcall(fn)       __define_initcall(fn, 0)#define core_initcall(fn)       __define_initcall(fn, 1)#define core_initcall_sync(fn)      __define_initcall(fn, 1s)#define postcore_initcall(fn)       __define_initcall(fn, 2)#define postcore_initcall_sync(fn)  __define_initcall(fn, 2s)#define arch_initcall(fn)       __define_initcall(fn, 3)#define arch_initcall_sync(fn)      __define_initcall(fn, 3s)#define subsys_initcall(fn)     __define_initcall(fn, 4)#define subsys_initcall_sync(fn)    __define_initcall(fn, 4s)#define fs_initcall(fn)         __define_initcall(fn, 5)#define fs_initcall_sync(fn)        __define_initcall(fn, 5s)#define rootfs_initcall(fn)     __define_initcall(fn, rootfs)#define device_initcall(fn)     __define_initcall(fn, 6)#define device_initcall_sync(fn)    __define_initcall(fn, 6s)#define late_initcall(fn)       __define_initcall(fn, 7)#define late_initcall_sync(fn)      __define_initcall(fn, 7s)#define __initcall(fn) device_initcall(fn)static int __init populate_rootfs(void){/* Load the built in initramfs */char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);//解压unpack initrdif (err)panic("%s", err); /* Failed to decompress INTERNAL initramfs *//* If available load the bootloader supplied initrd */if (initrd_start && !IS_ENABLED(CONFIG_INITRAMFS_FORCE)) {//若initrd_start为0,说明无效,不执行#ifdef CONFIG_BLK_DEV_RAMint fd;printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");err = unpack_to_rootfs((char *)initrd_start,initrd_end - initrd_start);if (!err)goto done;clean_rootfs();unpack_to_rootfs(__initramfs_start, __initramfs_size);//开始解压printk(KERN_INFO "rootfs image is not initramfs (%s)""; looks like an initrd\n", err);fd = ksys_open("/initrd.image",O_WRONLY|O_CREAT, 0700);if (fd >= 0) {ssize_t written = xwrite(fd, (char *)initrd_start,initrd_end - initrd_start);if (written != initrd_end - initrd_start)pr_err("/initrd.image: incomplete write (%zd != %ld)\n",written, initrd_end - initrd_start);ksys_close(fd);}done:/* empty statement */;#elseprintk(KERN_INFO "Unpacking initramfs...\n");err = unpack_to_rootfs((char *)initrd_start,initrd_end - initrd_start);if (err)printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);#endif}free_initrd();flush_delayed_fput();return 0;}rootfs_initcall(populate_rootfs);void __init prepare_namespace(void){int is_floppy;int err;if (root_delay) {//将根文件系统存放在USB或者SCSI设备上,kernel需要等待这些消耗时间的设备驱动加载完毕printk(KERN_INFO "Waiting %d sec before mounting root device...\n",root_delay);ssleep(root_delay);}/** wait for the known devices to complete their probing** Note: this is a potential source of long boot delays.* For example, it is not atypical to wait 5 seconds here* for the touchpad of a laptop to initialize.*/wait_for_device_probe();//等待根文件系统所在的设备探测函数的完成md_run_setup();if (saved_root_name[0]) {//存放kernel参数的root=指定的参数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())//挂载initrdgoto out;//指定mount_initrd为true,即没有指定函数initrd_load中mount的话,则重新realfs的mount操作/* 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(5);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");ksys_mount(".", "/", NULL, MS_MOVE, NULL);//移动根文件系统的根目录为/ksys_chroot(".");//将当前目录当作系统的根目录,至此切换到实际根目录系统#ifdef CONFIG_BLOCK/* recreate the /dev/root */err = create_dev("/dev/root", ROOT_DEV);if (err < 0)pr_emerg("Failed to create /dev/root: %d\n", err);#endif}void __init mount_block_root(char *name, int flags){struct page *page = alloc_page(GFP_KERNEL);char *fs_names = page_address(page);//申请资源char *p;#ifdef CONFIG_BLOCKchar b[BDEVNAME_SIZE];#elseconst char *b = name;#endifget_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);//调用do_mount_root进行gauzeswitch (err) {case 0:goto out;case -EACCES:case -EINVAL:continue;}/** Allow the user to distinguish between failed sys_open* and bad superblock on root device.* and give them a list of the available devices*/#ifdef CONFIG_BLOCK__bdevname(ROOT_DEV, b);#endifprintk("VFS: Cannot open root device \"%s\" or %s: error %d\n",root_device_name, b, err);printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");//提示错误信息printk_all_partitions();#ifdef CONFIG_DEBUG_BLOCK_EXT_DEVTprintk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify ""explicit textual name for \"root=\" boot option.\n");#endifpanic("VFS: Unable to mount root fs on %s", b);}if (!(flags & SB_RDONLY)) {flags |= SB_RDONLY;goto retry;}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);#endifpanic("VFS: Unable to mount root fs on %s", b);out:put_page(page);}static int __init do_mount_root(char *name, char *fs, int flags, void *data){struct super_block *s;int err = ksys_mount(name, "/root", fs, flags, data);//挂载文件系统,这里的name为/dev/root,fs为文件类型if (err)return err;ksys_chdir("/root");//改变到/root目录s = current->fs->pwd.dentry->d_sb;ROOT_DEV = s->s_dev;printk(KERN_INFO"VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",s->s_type->name,sb_rdonly(s) ? " readonly" : "",MAJOR(ROOT_DEV), MINOR(ROOT_DEV));//显示主次设备号return 0;}void __init mount_root(void){#ifdef CONFIG_ROOT_NFSif (ROOT_DEV == Root_NFS) {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_FDif (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {/* rd_doload is 2 for a dual initrd/ramload setup */if (rd_doload==2) {if (rd_load_disk(1)) {ROOT_DEV = Root_RAM1;root_device_name = NULL;}} elsechange_floppy("root floppy");}#endif#ifdef CONFIG_BLOCK{int err = create_dev("/dev/root", ROOT_DEV);if (err < 0)pr_emerg("Failed to create /dev/root: %d\n", err);mount_block_root("/dev/root", root_mountflags);//挂载文件系统}#endif}

五、总结

通过对内核模块的init进行分析,使用initrd.img进行内存模块的加载,释放initrd后,最终才加载真正的文件系统。从虚拟内存文件系统,切换到真正的文件系统,第一阶段为第二阶段服务,主要是用来加载根文件系统以及根文件系统存储介质的驱动程序。initrd能够减小启动内核的体积并增加灵活性,从initrd所mount的根文件系统中装载需要的模块。

参考链接:
1、https://blog.csdn.net/yuntongsf/article/details/37607101
2、https://www.cnblogs.com/shangye/p/6260471.html
3、https://blog.csdn.net/guopeixin/article/details/5962482
4、https://www.linuxidc.com/Linux/2011-10/45448p2.htm

以下是新的个人博客的地址:
http://106.53.224.102:8080/wordpress-zh/feng_8071/linux-initrd根文件挂载分析/

Linux——initrd根文件挂载分析相关推荐

  1. Uboot启动内核和根文件系统命令分析

      uboot有两种启动 Linux 内核和rootfs的方法,一种是直接从flash(nand或emmc)启动,一种是从网络启动.这里面用到了两个非常重要的环境变量bootcmd 和 bootarg ...

  2. 基于SUSE Linux做NFS文件挂载

    linux文件挂载其实和windows文件共享原理差不多,由主机配置一个共享目录,客户端机器可以通过网络访问该共享目录. 下面以SUSE11为例子,简要描述下NFS文件挂载过程: 一.主机端(主机IP ...

  3. linux系统根分区挂载出错 系统无法,用虚拟机安装linux时显示“没有定义根文件系统,请到分区菜单以修正此错误”,是什么意思,肿么弄谢谢各位...

    你的wubi安装在过程中应该失败了.安装程序进入了硬盘安装的过程,此时要格盘建分区(通常是两个:swap和"/"根目录挂载点).Wubi安装很简单的. 你的问题我不是很明白,wub ...

  4. linux elf格式文件详细分析

    ELF(Executable and Linkable Format)是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东西.以及都以什么样的格式去放这些东西. ...

  5. linux raid member,文件挂载时报错“linux_raid_member”

    重装了一台系统,分区格式化后挂载一个磁盘出错 [root@CM-MM-sve-111 ~]# mount /dev/sdh1 /mnt mount: unknown filesystem type ' ...

  6. linux启动根文件失败报错:进程退出exitcode,Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b

    进程退出的 exitcode 错误信息 内核打印 1 Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b 分 ...

  7. linux中典型文件档案分析

    /etc/passwd 中一行记录的最后一个字段(字段间以:分割)为对应用户登录后取得的默认shell.倒数第二个字段为登录后默认的当下工作目录,即pwd查看到的目录. /etc/services 中 ...

  8. linux如何拿到文件的返回值,linux 怎么判断文件挂载是否成功,根据什么样的返回值?...

    了解你的意思,首先,test命令是判断某一个特定的文件相关信息,也就是当你使用test这个命令的时候,你是清楚它叫什么名字的(只是你不知道它的相关信息).如果你要判断比如你说的以hbc*开头的一类文件 ...

  9. 第3阶段——内核启动分析之prepare_namespace()如何挂载根文件系统和mtd分区介绍(6)...

    内核启动并初始化后,最终目的是像Windows一样能启动应用程序,在windows中每个应用程序都存在C盘.D盘等,而linux中每个应用程序是存放在根文件系统里面,那么挂载根文件系统在哪里,怎么实现 ...

最新文章

  1. WINDOWSPHONE STUDY1:创建一个 Windows Phone 7 下的简单 RSS 阅读器
  2. windows平台 python生成 pyd文件
  3. leetcode1423. 可获得的最大点数
  4. 手把手教安装java开发环境_手把手教你配置java开发环境-java环境变量设置
  5. 【原创】vegas提示NTDLL.DLL出错的解决办法
  6. Pycharm中设置py文件头部注释信息
  7. [转载] Python str title()方法
  8. fir.im Weekly - 如何打造真正的工程师文化
  9. php把字符串日期转成时间戳,php怎样把日期转成时间戳
  10. sql 时间日期格式转换
  11. 【2017宁波联考】生成树
  12. html5学习开发指南
  13. Keil、uVision、RealView、MDK、Keil C51之间的区别
  14. 总结2016年国内外的AR/VR产品
  15. XP系统启动时滚动条总是时间很长
  16. 博弈论之海盗分金(最严谨)
  17. 基于ZigBee的WPAN网络配置应用
  18. 《清华园日记》读后感
  19. APP安全环节缺失,手游运营商如何应对APP破解困境
  20. 为什么要使用flowable工作流

热门文章

  1. TextRank算法学习及使用
  2. np.astype()函数
  3. 制作ubuntu 18.04启动盘并安装系统+必要配置
  4. 解决mysql [1045] Access denied for user 'root'@'192.168.180.248' (using password: YES)
  5. 【互联网文化创意设计】“互动”从这两个构成的字来说,“互”是“交替、相互”的意思
  6. Ubuntu使用OneDrive记录:更换账户或修改密码之后重新登
  7. Package包的理解
  8. python列表元素求和_如何在python语言使用不同方法实现列表元素求和
  9. 推荐几款让人爱不释手的奶油风软装好物
  10. 浙江事业单位考不考计算机专业知识,浙江事业单位考试计算机相关综合知识,看哪些?...