免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4528 | 回复: 0
打印 上一主题 下一主题

[转贴]分析内核初始化时根内存盘的加载过程(init/main.c) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-02-09 09:45 |只看该作者 |倒序浏览
原文出自:http://www.linuxforum.net
作者:opera
=============================

概述
====
1)当内核配置了内存盘时, 内核在初始化时可以将软盘加载到内存盘中作为根盘. 当同时配置了初始化内
存盘(Initail RAM Disk)时, 内核在初始化时可以在安装主盘之前, 通过引导程序所加载的initrd文件建
立一个内存初始化盘, 首先将它安装成根文件系统, 然后执行其根目录下的linuxrc 文件, 可用于在安装
主盘之前加载一些内核模块. 等到linuxrc 程序退出后, 再将主盘安装成根文件系统, 并将内存初始化盘
转移安装到其/initrd目录下.

2)当主盘就是initrd所生成的内存初始化盘时, 不再进行重新安装, 在DOS下用loadlin加载的抢救盘就是
这种工作方式.

3)引导程序所加载的initrd为文件系统的映象文件, 可以是gzip压缩的, 也可以是不压缩的. 能够识别的
文件系统有minix,ext2,romfs三种.

4)当内核的根盘为软盘时, 内核初始化时会测试软盘的指定部位是否存在文件系统或压缩文件映象, 然后
将之加载或解压到内存盘中作为根盘. 这是单张抢救软盘的工作方式.

有关代码
========

  1. ; init/main.c

  2. #ifdef CONFIG_BLK_DEV_INITRD
  3. kdev_t real_root_dev; 启动参数所设定的根盘设备
  4. #endif

  5. asmlinkage void __init start_kernel(void)
  6. {
  7.         char * command_line;
  8.         unsigned long mempages;
  9.         extern char saved_command_line[];

  10.         lock_kernel();
  11.         printk(linux_banner);
  12.         setup_arch(&command_line); arch/i386/kernel/setup.c中,初始化initrd_start和initrd_end两个变量

  13.         ...

  14. #ifdef CONFIG_BLK_DEV_INITRD
  15.         if (initrd_start && !initrd_below_start_ok &&
  16.                         initrd_start < min_low_pfn << PAGE_SHIFT) {
  17.                 ; min_low_pfn为内核末端_end所开始的物理页号,initrd_start,initrd_end在rd.c中定义
  18.                 printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
  19.                     "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
  20.                 initrd_start = 0;
  21.         }
  22. #endif
  23.         ...
  24.        
  25.         kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); 创建init进程
  26.         unlock_kernel();
  27.         current->;need_resched = 1;
  28.         cpu_idle();
  29. }
  30. static int init(void * unused)
  31. {
  32.         lock_kernel();
  33.         do_basic_setup();

  34.         /*
  35.          * Ok, we have completed the initial bootup, and
  36.          * we're essentially up and running. Get rid of the
  37.          * initmem segments and start the user-mode stuff..
  38.          */
  39.         free_initmem();
  40.         unlock_kernel();

  41.         if (open("/dev/console", O_RDWR, 0) < 0)
  42.                 printk("Warning: unable to open an initial console.\n");

  43.         (void) dup(0);
  44.         (void) dup(0);
  45.        
  46.         /*
  47.          * We try each of these until one succeeds.
  48.          *
  49.          * The Bourne shell can be used instead of init if we are
  50.          * trying to recover a really broken machine.
  51.          */

  52.         if (execute_command)
  53.                 execve(execute_command,argv_init,envp_init);
  54.         execve("/sbin/init",argv_init,envp_init);
  55.         execve("/etc/init",argv_init,envp_init);
  56.         execve("/bin/init",argv_init,envp_init);
  57.         execve("/bin/sh",argv_init,envp_init);
  58.         panic("No init found.  Try passing init= option to kernel.");
  59. }

  60. static void __init do_basic_setup(void)
  61. {
  62. #ifdef CONFIG_BLK_DEV_INITRD
  63.         int real_root_mountflags;
  64. #endif

  65.         ...

  66. #ifdef CONFIG_BLK_DEV_INITRD
  67.         real_root_dev = ROOT_DEV; ROOT_DEV为所请求根文件系统的块设备
  68.         real_root_mountflags = root_mountflags;
  69.         if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY;
  70.         else mount_initrd =0;
  71. #endif

  72.         start_context_thread();
  73.         do_initcalls();        会调用partition_setup()中加载内存盘

  74.         /* .. filesystems .. */
  75.         filesystem_setup();

  76.         /* Mount the root filesystem.. */
  77.         mount_root();
  78.         mount_devfs_fs ();

  79. #ifdef CONFIG_BLK_DEV_INITRD
  80.         root_mountflags = real_root_mountflags;
  81.         if (mount_initrd && ROOT_DEV != real_root_dev
  82.             && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) {
  83.                 ; 如果当前根盘为initrd所建立的内存盘
  84.                 int error;
  85.                 int i, pid;

  86.                 pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); 创建新的任务去执行程序/linuxrc
  87.                 if (pid>;0)
  88.                         while (pid != wait(&i)); 等待linuxrc进程退出
  89.                 if (MAJOR(real_root_dev) != RAMDISK_MAJOR
  90.                      || MINOR(real_root_dev) != 0) {
  91.                         ; 如果原来的根盘不是0号内存盘,则使用原来的根文件系统,
  92.                         ; 并且将内存盘转移到其/initrd目录下
  93.                         error = change_root(real_root_dev,"/initrd");
  94.                         if (error)
  95.                                 printk(KERN_ERR "Change root to /initrd: "
  96.                                     "error %d\n",error);
  97.                 }
  98.         }
  99. #endif
  100. }

  101. #ifdef CONFIG_BLK_DEV_INITRD
  102. static int do_linuxrc(void * shell)
  103. {
  104.         static char *argv[] = { "linuxrc", NULL, };

  105.         close(0);close(1);close(2);
  106.         setsid(); 设置新的session号
  107.         (void) open("/dev/console",O_RDWR,0);
  108.         (void) dup(0);
  109.         (void) dup(0);
  110.         return execve(shell, argv, envp_init);
  111. }

  112. #endif

  113. ; arch/i386/kernel/setup.c

  114. #define RAMDISK_IMAGE_START_MASK          0x07FF
  115. #define RAMDISK_PROMPT_FLAG                0x8000
  116. #define RAMDISK_LOAD_FLAG                0x4000       

  117. #define PARAM        ((unsigned char *)empty_zero_page)
  118. #define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8)) 可用rdev设置的参数
  119. #define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
  120. #define INITRD_START (*(unsigned long *) (PARAM+0x218)) 初始化盘映象起始物理地址
  121. #define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))  初始化盘字节数

  122. void __init setup_arch(char **cmdline_p)
  123. {
  124.         ...
  125. #ifdef CONFIG_BLK_DEV_RAM
  126.         rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; 以块为单位
  127.         rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
  128.         rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
  129. #endif
  130.         ...
  131. #ifdef CONFIG_BLK_DEV_INITRD
  132.         if (LOADER_TYPE && INITRD_START) {
  133.                 if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
  134.                         ; max_low_pfn表示内核空间1G范围以下最大允许的物理页号
  135.                         reserve_bootmem(INITRD_START, INITRD_SIZE);
  136.                         initrd_start =
  137.                                 INITRD_START ? INITRD_START + PAGE_OFFSET : 0; 转变为内核逻辑地址
  138.                         initrd_end = initrd_start+INITRD_SIZE;
  139.                 }
  140.                 else {
  141.                         printk("initrd extends beyond end of memory "
  142.                             "(0x%08lx >; 0x%08lx)\ndisabling initrd\n",
  143.                             INITRD_START + INITRD_SIZE,
  144.                             max_low_pfn << PAGE_SHIFT);
  145.                         initrd_start = 0;
  146.                 }
  147.         }
  148. #endif
  149.         ...
  150. }

  151. ; fs/partitions/check.c:

  152. int __init partition_setup(void)
  153. {
  154.         device_init();        包含ramdisk设备的初始化

  155. #ifdef CONFIG_BLK_DEV_RAM
  156. #ifdef CONFIG_BLK_DEV_INITRD
  157.         if (initrd_start && mount_initrd) initrd_load();
  158.                 ;如果启动时加载了initrd文件,则用它去初始化根内存盘
  159.         else
  160. #endif
  161.         rd_load(); 如果内核配置了内存盘并且根盘指定为软盘则试图将软盘加载为根内存盘
  162. #endif
  163.         return 0;
  164. }
  165. __initcall(partition_setup);

  166. ; drivers/block/rd.c:

  167. int rd_doload;                        /* 1 = load RAM disk, 0 = don't load */
  168. int rd_prompt = 1;                /* 1 = prompt for RAM disk, 0 = don't prompt */
  169. int rd_image_start;                /* starting block # of image */
  170. #ifdef CONFIG_BLK_DEV_INITRD
  171. unsigned long initrd_start, initrd_end;
  172. int mount_initrd = 1;                /* zero if initrd should not be mounted */
  173. int initrd_below_start_ok;

  174. void __init rd_load(void)
  175. {
  176.         rd_load_disk(0); 加载到0号内存盘
  177. }
  178. void __init rd_load_secondary(void)
  179. {
  180.         rd_load_disk(1); 加载到1号内存盘
  181. }
  182. static void __init rd_load_disk(int n)
  183. {
  184. #ifdef CONFIG_BLK_DEV_INITRD
  185.         extern kdev_t real_root_dev;
  186. #endif

  187.         if (rd_doload == 0)
  188.                 return;

  189.         if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR 如果根盘是不软盘
  190. #ifdef CONFIG_BLK_DEV_INITRD
  191.                 && MAJOR(real_root_dev) != FLOPPY_MAJOR
  192. #endif
  193.         )
  194.                 return;

  195.         if (rd_prompt) {
  196. #ifdef CONFIG_BLK_DEV_FD
  197.                 floppy_eject();
  198. #endif
  199. #ifdef CONFIG_MAC_FLOPPY
  200.                 if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR)
  201.                         swim3_fd_eject(MINOR(ROOT_DEV));
  202.                 else if(MAJOR(real_root_dev) == FLOPPY_MAJOR)
  203.                         swim3_fd_eject(MINOR(real_root_dev));
  204. #endif
  205.                 printk(KERN_NOTICE
  206.                        "VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER\n");
  207.                 wait_for_keypress();
  208.         }

  209.         rd_load_image(ROOT_DEV,rd_image_start, n); 将根软盘加载到n号内存盘

  210. }
  211. void __init initrd_load(void)
  212. {
  213.         ; 使用initrd设备盘作为源盘去建立内存根盘
  214.         rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),rd_image_start,0);
  215. }
  216. static void __init rd_load_image(kdev_t device, int offset, int unit)
  217. {
  218.         struct inode *inode, *out_inode;
  219.         struct file infile, outfile;
  220.         struct dentry in_dentry, out_dentry;
  221.         mm_segment_t fs;
  222.         kdev_t ram_device;
  223.         int nblocks, i;
  224.         char *buf;
  225.         unsigned short rotate = 0;
  226.         unsigned short devblocks = 0;
  227.         char rotator[4] = { '|' , '/' , '-' , '\\' };

  228.         ram_device = MKDEV(MAJOR_NR, unit); 建立输出内存盘设备号

  229.         if ((inode = get_empty_inode()) == NULL)
  230.                 return;
  231.         memset(&infile, 0, sizeof(infile));
  232.         memset(&in_dentry, 0, sizeof(in_dentry));
  233.         infile.f_mode = 1; /* read only */
  234.         infile.f_dentry = &in_dentry;
  235.         in_dentry.d_inode = inode;
  236.         infile.f_op = &def_blk_fops;
  237.         init_special_inode(inode, S_IFBLK | S_IRUSR, kdev_t_to_nr(device));
  238.                
  239.         if ((out_inode = get_empty_inode()) == NULL)
  240.                 goto free_inode;
  241.         memset(&outfile, 0, sizeof(outfile));
  242.         memset(&out_dentry, 0, sizeof(out_dentry));
  243.         outfile.f_mode = 3; /* read/write */
  244.         outfile.f_dentry = &out_dentry;
  245.         out_dentry.d_inode = out_inode;
  246.         outfile.f_op = &def_blk_fops;
  247.         init_special_inode(out_inode, S_IFBLK | S_IRUSR | S_IWUSR, kdev_t_to_nr(ram_device));
  248.                
  249.         if (blkdev_open(inode, &infile) != 0) 打开输入盘文件
  250.                 goto free_inode;
  251.         if (blkdev_open(out_inode, &outfile) != 0) 打开输出内存盘文件
  252.                 goto free_inodes;

  253.         fs = get_fs();
  254.         set_fs(KERNEL_DS);
  255.        
  256.         nblocks = identify_ramdisk_image(device, &infile, offset); 鉴定输入盘的文件类型
  257.         if (nblocks < 0) 出错
  258.                 goto done;

  259.         if (nblocks == 0) { 表示输入盘是gzip文件
  260. #ifdef BUILD_CRAMDISK
  261.                 if (crd_load(&infile, &outfile) == 0) 将输入盘文件解压到输出盘文件中去
  262.                         goto successful_load;
  263. #else
  264.                 printk(KERN_NOTICE
  265.                        "RAMDISK: Kernel does not support compressed "
  266.                        "RAM disk images\n");
  267. #endif
  268.                 goto done;
  269.         }

  270.         /*
  271.          * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so
  272.          * rd_load_image will work only with filesystem BLOCK_SIZE wide!
  273.          * So make sure to use 1k blocksize while generating ext2fs
  274.          * ramdisk-images.
  275.          */
  276.         if (nblocks >; (rd_length[unit] >;>; BLOCK_SIZE_BITS)) {
  277.                 ; 如果输入盘的尺寸超过了输出内存盘的允许尺寸
  278.                 printk("RAMDISK: image too big! (%d/%ld blocks)\n",
  279.                        nblocks, rd_length[unit] >;>; BLOCK_SIZE_BITS);
  280.                 goto done;
  281.         }
  282.                
  283.         /*
  284.          * OK, time to copy in the data
  285.          */
  286.         buf = kmalloc(BLOCK_SIZE, GFP_KERNEL);
  287.         if (buf == 0) {
  288.                 printk(KERN_ERR "RAMDISK: could not allocate buffer\n");
  289.                 goto done;
  290.         }

  291.         if (blk_size[MAJOR(device)])
  292.                 devblocks = blk_size[MAJOR(device)][MINOR(device)]; 取输入盘的容量

  293. #ifdef CONFIG_BLK_DEV_INITRD
  294.         if (MAJOR(device) == MAJOR_NR && MINOR(device) == INITRD_MINOR)
  295.                 devblocks = nblocks; 如果输入是初始化内存盘,则盘的容量为它的实际尺寸
  296. #endif

  297.         if (devblocks == 0) {
  298.                 printk(KERN_ERR "RAMDISK: could not determine device size\n");
  299.                 goto done;
  300.         }

  301.         printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%d disk%s] into ram disk... ",
  302.                 nblocks, ((nblocks-1)/devblocks)+1, nblocks>;devblocks ? "s" : "");
  303.         for (i=0; i < nblocks; i++) {
  304.                 if (i && (i % devblocks == 0)) {
  305.                         printk("done disk #%d.\n", i/devblocks);
  306.                         rotate = 0;
  307.                         invalidate_buffers(device); 使输入盘设备缓冲区无效
  308.                         if (infile.f_op->;release)
  309.                                 infile.f_op->;release(inode, &infile);
  310.                         printk("Please insert disk #%d and press ENTER\n", i/devblocks+1);
  311.                         wait_for_keypress();
  312.                         if (blkdev_open(inode, &infile) != 0)  {
  313.                                 printk("Error opening disk.\n");
  314.                                 goto done;
  315.                         }
  316.                         infile.f_pos = 0;
  317.                         printk("Loading disk #%d... ", i/devblocks+1);
  318.                 }
  319.                 infile.f_op->;read(&infile, buf, BLOCK_SIZE, &infile.f_pos);
  320.                 outfile.f_op->;write(&outfile, buf, BLOCK_SIZE, &outfile.f_pos);
  321. #if !defined(CONFIG_ARCH_S390)
  322.                 if (!(i % 16)) {
  323.                         printk("%c\b", rotator[rotate & 0x3]);
  324.                         rotate++;
  325.                 }
  326. #endif
  327.         }
  328.         printk("done.\n");
  329.         kfree(buf);

  330. successful_load:
  331.         invalidate_buffers(device);
  332.         ROOT_DEV = MKDEV(MAJOR_NR, unit); 将根盘设备设置为当前加载的内存盘
  333.         if (ROOT_DEVICE_NAME != NULL) strcpy (ROOT_DEVICE_NAME, "rd/0");

  334. done:
  335.         if (infile.f_op->;release)
  336.                 infile.f_op->;release(inode, &infile);
  337.         set_fs(fs);
  338.         return;
  339. free_inodes: /* free inodes on error */
  340.         iput(out_inode);
  341.         blkdev_put(inode->;i_bdev, BDEV_FILE);
  342. free_inode:
  343.         iput(inode);
  344. }
  345. int __init
  346. identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)
  347. {
  348.         const int size = 512;
  349.         struct minix_super_block *minixsb;
  350.         struct ext2_super_block *ext2sb;
  351.         struct romfs_super_block *romfsb;
  352.         int nblocks = -1;
  353.         unsigned char *buf;

  354.         buf = kmalloc(size, GFP_KERNEL);
  355.         if (buf == 0)
  356.                 return -1;

  357.         minixsb = (struct minix_super_block *) buf;
  358.         ext2sb = (struct ext2_super_block *) buf;
  359.         romfsb = (struct romfs_super_block *) buf;
  360.         memset(buf, 0xe5, size);

  361.         /*
  362.          * Read block 0 to test for gzipped kernel
  363.          */
  364.         if (fp->;f_op->;llseek)
  365.                 fp->;f_op->;llseek(fp, start_block * BLOCK_SIZE, 0);
  366.         fp->;f_pos = start_block * BLOCK_SIZE;
  367.        
  368.         fp->;f_op->;read(fp, buf, size, &fp->;f_pos);
  369.         ; 读取offset开始的512字节
  370.         /*
  371.          * If it matches the gzip magic numbers, return -1
  372.          */
  373.         if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) {
  374.                 printk(KERN_NOTICE
  375.                        "RAMDISK: Compressed image found at block %d\n",
  376.                        start_block);
  377.                 nblocks = 0;
  378.                 goto done;
  379.         }

  380.         /* romfs is at block zero too */
  381.         if (romfsb->;word0 == ROMSB_WORD0 &&
  382.             romfsb->;word1 == ROMSB_WORD1) {
  383.                 printk(KERN_NOTICE
  384.                        "RAMDISK: romfs filesystem found at block %d\n",
  385.                        start_block);
  386.                 nblocks = (ntohl(romfsb->;size)+BLOCK_SIZE-1)>;>;BLOCK_SIZE_BITS;
  387.                 goto done;
  388.         }

  389.         /*
  390.          * Read block 1 to test for minix and ext2 superblock
  391.          */
  392.         if (fp->;f_op->;llseek)
  393.                 fp->;f_op->;llseek(fp, (start_block+1) * BLOCK_SIZE, 0);
  394.         fp->;f_pos = (start_block+1) * BLOCK_SIZE;

  395.         fp->;f_op->;read(fp, buf, size, &fp->;f_pos);
  396.                
  397.         /* Try minix */
  398.         if (minixsb->;s_magic == MINIX_SUPER_MAGIC ||
  399.             minixsb->;s_magic == MINIX_SUPER_MAGIC2) {
  400.                 printk(KERN_NOTICE
  401.                        "RAMDISK: Minix filesystem found at block %d\n",
  402.                        start_block);
  403.                 nblocks = minixsb->;s_nzones << minixsb->;s_log_zone_size;
  404.                 goto done;
  405.         }

  406.         /* Try ext2 */
  407.         if (ext2sb->;s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) {
  408.                 printk(KERN_NOTICE
  409.                        "RAMDISK: ext2 filesystem found at block %d\n",
  410.                        start_block);
  411.                 nblocks = le32_to_cpu(ext2sb->;s_blocks_count);
  412.                 goto done;
  413.         }

  414.         printk(KERN_NOTICE
  415.                "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n",
  416.                start_block);
  417.        
  418. done:
  419.         if (fp->;f_op->;llseek)
  420.                 fp->;f_op->;llseek(fp, start_block * BLOCK_SIZE, 0);
  421.         fp->;f_pos = start_block * BLOCK_SIZE;       

  422.         kfree(buf);
  423.         return nblocks;
  424. }

  425. ; fs/super.c
  426. void __init mount_root(void)
  427. {
  428.         struct file_system_type * fs_type;
  429.         struct super_block * sb;
  430.         struct vfsmount *vfsmnt;
  431.         struct block_device *bdev = NULL;
  432.         mode_t mode;
  433.         int retval;
  434.         void *handle;
  435.         char path[64];
  436.         int path_start = -1;


  437. #ifdef CONFIG_BLK_DEV_FD
  438.         if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { 当根盘还是软盘,表示没有加载过内存盘
  439. #ifdef CONFIG_BLK_DEV_RAM
  440.                 extern int rd_doload;
  441.                 extern void rd_load_secondary(void);
  442. #endif
  443.                 floppy_eject();
  444. #ifndef CONFIG_BLK_DEV_RAM
  445.                 printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");
  446. #else
  447.                 /* rd_doload is 2 for a dual initrd/ramload setup */
  448.                 ; 只有当加载了initrd但没有释放到内存盘中(mount_inird=0)才有可能到这一步
  449.                 if(rd_doload==2)
  450.                         rd_load_secondary(); 加载另一张软盘到1号内存盘作为根盘
  451.                 else
  452. #endif
  453.                 {
  454.                         printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
  455.                         wait_for_keypress();
  456.                 }
  457.         }
  458. #endif

  459.         devfs_make_root (root_device_name);
  460.         handle = devfs_find_handle (NULL, ROOT_DEVICE_NAME,
  461.                                     MAJOR (ROOT_DEV), MINOR (ROOT_DEV),
  462.                                     DEVFS_SPECIAL_BLK, 1);
  463.         if (handle)  /*  Sigh: bd*() functions only paper over the cracks  */
  464.         {
  465.             unsigned major, minor;

  466.             devfs_get_maj_min (handle, &major, &minor);
  467.             ROOT_DEV = MKDEV (major, minor);
  468.         }

  469.         /*
  470.          * Probably pure paranoia, but I'm less than happy about delving into
  471.          * devfs crap and checking it right now. Later.
  472.          */
  473.         if (!ROOT_DEV)
  474.                 panic("I have no root and I want to scream");

  475.         bdev = bdget(kdev_t_to_nr(ROOT_DEV));
  476.         if (!bdev)
  477.                 panic(__FUNCTION__ ": unable to allocate root device");
  478.         bdev->;bd_op = devfs_get_ops (handle);
  479.         path_start = devfs_generate_path (handle, path + 5, sizeof (path) - 5);
  480.         mode = FMODE_READ;
  481.         if (!(root_mountflags & MS_RDONLY))
  482.                 mode |= FMODE_WRITE;
  483.         retval = blkdev_get(bdev, mode, 0, BDEV_FS);
  484.         if (retval == -EROFS) {
  485.                 root_mountflags |= MS_RDONLY;
  486.                 retval = blkdev_get(bdev, FMODE_READ, 0, BDEV_FS);
  487.         }
  488.         if (retval) {
  489.                 /*
  490.                  * Allow the user to distinguish between failed open
  491.                  * and bad superblock on root device.
  492.                  */
  493.                 printk ("VFS: Cannot open root device \"%s\" or %s\n",
  494.                         root_device_name, kdevname (ROOT_DEV));
  495.                 printk ("Please append a correct \"root=\" boot option\n");
  496.                 panic("VFS: Unable to mount root fs on %s",
  497.                         kdevname(ROOT_DEV));
  498.         }

  499.         check_disk_change(ROOT_DEV);
  500.         sb = get_super(ROOT_DEV); 取根盘的超级块
  501.         if (sb) {
  502.                 fs_type = sb->;s_type;
  503.                 goto mount_it;
  504.         }

  505.         read_lock(&file_systems_lock);
  506.         for (fs_type = file_systems ; fs_type ; fs_type = fs_type->;next) {
  507.                   if (!(fs_type->;fs_flags & FS_REQUIRES_DEV))
  508.                           continue; 根文件系统必须依赖于块设备
  509.                 if (!try_inc_mod_count(fs_type->;owner))
  510.                         continue; 当文件系统模块正在删除过程中
  511.                 read_unlock(&file_systems_lock);
  512.                   sb = read_super(ROOT_DEV,bdev,fs_type,root_mountflags,NULL,1); 建立根盘的超级块结构
  513.                 if (sb)
  514.                         goto mount_it;
  515.                 read_lock(&file_systems_lock);
  516.                 put_filesystem(fs_type); 释放对文件系统模块的引用
  517.         }
  518.         read_unlock(&file_systems_lock);
  519.         panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));

  520. mount_it:
  521.         printk ("VFS: Mounted root (%s filesystem)%s.\n",
  522.                 fs_type->;name,
  523.                 (sb->;s_flags & MS_RDONLY) ? " readonly" : "");
  524.         if (path_start >;= 0) {
  525.                 devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT,
  526.                                   path + 5 + path_start, NULL, NULL);
  527.                 memcpy (path + path_start, "/dev/", 5);
  528.                 vfsmnt = add_vfsmnt(NULL, sb->;s_root, path + path_start);
  529.         }
  530.         else
  531.                 vfsmnt = add_vfsmnt(NULL, sb->;s_root, "/dev/root"); 建立根盘的安装结构
  532.         /* FIXME: if something will try to umount us right now... */
  533.         if (vfsmnt) {
  534.                 set_fs_root(current->;fs, vfsmnt, sb->;s_root); 设置当前进程的根盘和根目录
  535.                 set_fs_pwd(current->;fs, vfsmnt, sb->;s_root);  设置当前进程的当前盘和当前目录
  536.                 if (bdev)
  537.                         bdput(bdev); /* sb holds a reference */
  538.                 return;
  539.         }
  540.         panic("VFS: add_vfsmnt failed for root fs");
  541. }

  542. #ifdef CONFIG_BLK_DEV_INITRD
  543. int __init change_root(kdev_t new_root_dev,const char *put_old)
  544. {        以new_root_dev作为根盘重新安装根文件系统,原来的根转移到put_old目录下
  545.         struct vfsmount *old_rootmnt;
  546.         struct nameidata devfs_nd, nd;
  547.         int error = 0;

  548.         read_lock(&current->;fs->;lock);
  549.         old_rootmnt = mntget(current->;fs->;rootmnt); 取当前进程的根盘安装结构
  550.         read_unlock(&current->;fs->;lock);
  551.         /*  First unmount devfs if mounted  */
  552.         if (path_init("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd))
  553.                 error = path_walk("/dev", &devfs_nd);
  554.         if (!error) {
  555.                 if (devfs_nd.mnt->;mnt_sb->;s_magic == DEVFS_SUPER_MAGIC &&
  556.                     devfs_nd.dentry == devfs_nd.mnt->;mnt_root) {
  557.                         dput(devfs_nd.dentry);
  558.                         down(&mount_sem);
  559.                         /* puts devfs_nd.mnt */
  560.                         do_umount(devfs_nd.mnt, 0, 0);
  561.                         up(&mount_sem);
  562.                 } else
  563.                         path_release(&devfs_nd);
  564.         }
  565.         ROOT_DEV = new_root_dev;
  566.         mount_root(); 改变根盘设备重新安装根文件系统
  567. #if 1
  568.         shrink_dcache(); 清除目录项缓冲中所有自由的目录项
  569.         printk("change_root: old root has d_count=%d\n",
  570.                atomic_read(&old_rootmnt->;mnt_root->;d_count));
  571. #endif
  572.         mount_devfs_fs ();
  573.         /*
  574.          * Get the new mount directory
  575.          */
  576.         error = 0;
  577.         if (path_init(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))
  578.                 error = path_walk(put_old, &nd); 在新的根盘中寻找put_old目录
  579.         if (error) {
  580.                 int blivet;

  581.                 printk(KERN_NOTICE "Trying to unmount old root ... ");
  582.                 blivet = do_umount(old_rootmnt, 1, 0); 卸载原始的根盘
  583.                 if (!blivet) {
  584.                         printk("okay\n");
  585.                         return 0;
  586.                 }
  587.                 printk(KERN_ERR "error %d\n", blivet);
  588.                 return error;
  589.         }
  590.         /* FIXME: we should hold i_zombie on nd.dentry */
  591.         move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old");
  592.         mntput(old_rootmnt);
  593.         path_release(&nd);
  594.         return 0;
  595. }

  596. #endif

  597. static struct vfsmount *add_vfsmnt(struct nameidata *nd, 在虚拟文件系统中的安装点
  598.                                 struct dentry *root, 安装盘的根目录项
  599.                                 const char *dev_name) 安装盘名称
  600. {       
  601.         struct vfsmount *mnt;
  602.         struct super_block *sb = root->;d_inode->;i_sb;
  603.         char *name;

  604.         mnt = kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
  605.         if (!mnt)
  606.                 goto out;
  607.         memset(mnt, 0, sizeof(struct vfsmount));

  608.         if (nd || dev_name)
  609.                 mnt->;mnt_flags = MNT_VISIBLE;

  610.         /* It may be NULL, but who cares? */
  611.         if (dev_name) { 复制所安装安装盘名称字符串
  612.                 name = kmalloc(strlen(dev_name)+1, GFP_KERNEL);
  613.                 if (name) {
  614.                         strcpy(name, dev_name);
  615.                         mnt->;mnt_devname = name;
  616.                 }
  617.         }
  618.         mnt->;mnt_owner = current->;uid; 安装盘的安装者
  619.         atomic_set(&mnt->;mnt_count,1);
  620.         mnt->;mnt_sb = sb; 指向安装盘超级块结构

  621.         spin_lock(&dcache_lock);
  622.         if (nd && !IS_ROOT(nd->;dentry) && d_unhashed(nd->;dentry))
  623.                 goto fail;
  624.         mnt->;mnt_root = dget(root); 安装盘的根目录项
  625.         mnt->;mnt_mountpoint = nd ? dget(nd->;dentry) : dget(root); 指向上一层安装盘的根目录项
  626.         mnt->;mnt_parent = nd ? mntget(nd->;mnt) : mnt; 指向上一层安装盘的安装结构

  627.         if (nd) {
  628.                 list_add(&mnt->;mnt_child, &nd->;mnt->;mnt_mounts); 将安装盘作为上一层安装盘的子盘
  629.                 list_add(&mnt->;mnt_clash, &nd->;dentry->;d_vfsmnt); 使安装点目录项指向安装盘
  630.         } else {
  631.                 INIT_LIST_HEAD(&mnt->;mnt_child); 如果安装盘是根盘
  632.                 INIT_LIST_HEAD(&mnt->;mnt_clash);
  633.         }
  634.         INIT_LIST_HEAD(&mnt->;mnt_mounts);
  635.         list_add(&mnt->;mnt_instances, &sb->;s_mounts); 该安装结构是安装盘的一个安装实例
  636.         list_add(&mnt->;mnt_list, vfsmntlist.prev); 与所有的安装结构相连接
  637.         spin_unlock(&dcache_lock);
  638. out:
  639.         return mnt;
  640. fail:
  641.         spin_unlock(&dcache_lock);
  642.         if (mnt->;mnt_devname)
  643.                 kfree(mnt->;mnt_devname);
  644.         kfree(mnt);
  645.         return NULL;
  646. }
  647. static void move_vfsmnt(struct vfsmount *mnt, 源盘
  648.                         struct dentry *mountpoint, 目标目录
  649.                         struct vfsmount *parent, 目标盘
  650.                         const char *dev_name) 源盘名称
  651. {        将mnt安装盘以dev_name为名称移到parent盘的mountpoint目录下
  652.         struct dentry *old_mountpoint;
  653.         struct vfsmount *old_parent;
  654.         char *new_devname = NULL;

  655.         if (dev_name) {
  656.                 new_devname = kmalloc(strlen(dev_name)+1, GFP_KERNEL);
  657.                 if (new_devname)
  658.                         strcpy(new_devname, dev_name);
  659.         }

  660.         spin_lock(&dcache_lock);
  661.         old_mountpoint = mnt->;mnt_mountpoint; 取源盘的父盘根目录
  662.         old_parent = mnt->;mnt_parent; 取源盘的父盘

  663.         /* flip names */
  664.         if (new_devname) {
  665.                 if (mnt->;mnt_devname)
  666.                         kfree(mnt->;mnt_devname); 释放源盘的名称
  667.                 mnt->;mnt_devname = new_devname; 改为新的名称
  668.         }

  669.         /* flip the linkage */
  670.         mnt->;mnt_mountpoint = dget(mountpoint); 指向父盘的根目录
  671.         mnt->;mnt_parent = parent ? mntget(parent) : mnt; 指向父盘
  672.         list_del(&mnt->;mnt_clash); 删除源盘的安装点对源盘的链接
  673.         list_del(&mnt->;mnt_child); 删除源盘的作为子盘的链接
  674.         if (parent) {
  675.                 list_add(&mnt->;mnt_child, &parent->;mnt_mounts); 将源盘作为目标盘的子盘
  676.                 list_add(&mnt->;mnt_clash, &mountpoint->;d_vfsmnt); 使目标目录指向源盘
  677.         } else {
  678.                 INIT_LIST_HEAD(&mnt->;mnt_child);
  679.                 INIT_LIST_HEAD(&mnt->;mnt_clash);
  680.         }
  681.         spin_unlock(&dcache_lock);

  682.         /* put the old stuff */
  683.         dput(old_mountpoint);
  684.         if (old_parent != mnt)
  685.                 mntput(old_parent);
  686. }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP