文档库 最新最全的文档下载
当前位置:文档库 › Linux内核Ramdisk(initrd)机制

Linux内核Ramdisk(initrd)机制

Linux内核Ramdisk(initrd)机制
Linux内核Ramdisk(initrd)机制

摘要:

对于Linux用户来说,Ramdisk并不陌生,可是为什么需要它呢?本文对Ramdisk在内核启动过程中的作用,以及它的内部机制进行深入介绍。

标题

initrd 和initramfs在内核中的处理

临时的根目录rootfs的挂载

initrd的解压缩

老式的initrd的处理

cpio格式的initrd的处理

initrd实例分析:

在早期的Linux系统中,一般就只有软盘或者硬盘被用来作为Linux的根文件系统,因此很容易把这些设备的驱动程序集成到内核中。但是现在根文件系统可能保存在各种存储设备上,包括SCSI, SATA, U盘等等。因此把这些设备驱动程序全部编译到内核中显得不太方便。在Linux内核模块自动加载机制的介绍中,我们看到利用udevd可以实现实现内核模块的自动加载,因此我们希望根文件系统的设备驱动程序也能够实现自动加载。但是这里有一个矛盾,udevd是一个可执行文件,在根文件系统被挂载前,是不可能执行udevd 的,但是如果udevd没有启动,那就无法自动加载根根据系统设备的驱动程序,同时也无法在/dev目录下建立相应的设备节点。为了解决这个矛盾,于是出现了initrd(boot loader initialized RAM disk)。

initrd是一个被压缩过的小型根目录,这个目录中包含了启动阶段中必须的驱动模块,可执行文件和启动脚本。包括上面提到的udevd,当系统启动的时候,booload会把initrd 文件读到内存中,然后把initrd的起始地址告诉内核。内核在运行过程中会解压initrd,然后把initrd挂载为根目录,然后执行根目录中的/initrc脚本,您可以在这个脚本中运行initrd中的udevd,让它来自动加载设备驱动程序以及在/dev目录下建立必要的设备节点。在udevd自动加载磁盘驱动程序之后,就可以mount真正的根目录,并切换到这个根目录中。

您可以通过下面的方法来制作一个initrd文件。

# dd if=/dev/zero of=initrd.img bs=4k count=1024

# mkfs.ext2 -F initrd.img

# mount -o loop initrd.img /mnt

# cp -r miniroot/* /mnt

# umount /mnt

# gzip -9 initrd.img

通过上面的命令,我们制作了一个4M的initrd,其中miniroot就是一个根目录。最后我们得到一个名为initrd.img.gz的压缩文件。

利用initrd内核在启动阶段可以顺利的加载设备驱动程序,然而initrd存在以下缺点:

initrd大小是固定的,例如上面的压缩之前的initrd大小是4M(4k*1024),假设您的根目录(上例中的miniroot/)总大小仅仅是1M,它仍然要占用4M的空间。如果您在dd阶段指定大小为1M,后来发现不够用的时候,必须按照上面的步骤重新来一次。

initrd是一个虚拟的块设备,在上面的例子中,您可是使用fdisk对这个虚拟块设备进行分区。在内核中,对块设备的读写还要经过缓冲区管理模块,也就是说,当内核读取initrd 中的文件内容时,缓冲区管理层会认为下层的块设备速度比较慢,因此会启用预读和缓存功能。这样initrd本身就在内存中,同时块设备缓冲区管理层还会保存一部分内容。为了避免上述缺点,于是出现了initramfs,它的作用和initrd类似,您可以使用下面的方法来制作一个initramfs:

# find miniroot/ | cpio -c -o > initrd.img

# gzip initrd.img

这样得到的initrd.img大小是可变的,它取决于您的小型根目录miniroot/的总大小,由于首选使用cpio把根目录进行打包,因此这个initramfs又被称为cpio initrd. 在系统启动阶段,bootload除了从磁盘上机制内核镜像bzImage之外,还要加载initrd.img.gz,然后把initrd.img.gz 的起始地址传递给内核。能不能把这两个文件合二为一呢?答案是肯定的,在Linux 2.6的内核中,可以把initrd.img.gz链接到内核文件(ELF格式)的一个特殊的数据段中,这个段的名字为.init.ramfs。其中全局变量__initramfs_start和

__initramfs_end分别指向这个数据段的起始地址和结束地址。内核启动时对.init.ramfs 段中的数据进行解压,然后使用它作为临时的根文件系统。别看这个过程复杂,您只需要在make menuconfig中配置以下选项就可以了:

General setup --->

[*] Initial RAM filesystem and RAMdisk(initramfs/initrd)support

(../miniroot/) Initramfs source file(s)

其中../miniroot/就是我们的小型根目录。这样就只需要一个内核镜像文件就可以了。内核在启动过程中,必须对以下几种情况进行处理:

如果.init.ramfs数据段大小不为0(initramfs_end - initramfs_start != 0),就说明这是initrd集成在内核数据段中。并且是cpio的initrd.

initrd是由bootloader加载到内存中的,这时bootloader会把起始地址和结束地址传递给内核,内核中的全局initrd_start和initrd_end分别指向initrd的起始地址和结束地址。现在内核还需要判断这个initrd是新式的cpio格式的initrd还是旧的initrd.

initrd 和initramfs在内核中的处理

临时的根目录rootfs的挂载

首选在内核启动过程,会初始化rootfs文件系统,rootfs和tmpfs都是内存中的文件系统,其类型为ramfs. 然后会把这个rootfs挂载到根目录。其代码如下:

[start_kernel() -> vfs_caches_init() -> mnt_init()]

void __init mnt_init(void)

{ ......

init_rootfs();

init_mount_tree();

}init_rootfs()注册rootfs文件系统,代码如下:

static struct file_system_type rootfs_fs_type = {

.name = "rootfs",

.get_sb = rootfs_get_sb,

.kill_sb = kill_litter_super,};

int __init init_rootfs(void){

err = register_filesystem(&rootfs_fs_type);

...... return err;}

init_mount_tree会把rootfs挂载到/目录,代码如下:

static void __init init_mount_tree(void)

{

struct vfsmount *mnt;

struct mnt_namespace *ns;

mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); ......

set_fs_pwd(current->fs, ns->root, ns->root->mnt_root);

set_fs_root(current->fs, ns->root, ns->root->mnt_root);}

do_kern_mount()会调用前面注册的rootfs文件系统对象的rootfs_get_sb()函数,

[rootfs_get_sb() -> ramfs_fill_super() -> d_alloc_root()]struct dentry * d_alloc_root(struct inode * root_inode)

{

struct dentry *res = NULL;

if (root_inode)

{

static const struct qstr name = { .name = "/", .len = 1 };

res = d_alloc(NULL, &name);

if (res) {

res->d_sb = root_inode->i_sb;

res->d_parent = res;

d_instantiate(res, root_inode);

}

} return res;}

从上面的代码中的可以看出,这个rootfs的dentry对象的名字为"/",也就是根目录了。

initrd的解压缩

在start_kernel()的最后,调用rest_init(),rest_init()会建立一个新的内核进程,并在这个内核进程中执行kernel_init()函数,kernel_init()会调用populate_rootfs()来探测和解压initrd文件。这个函数需要处理上面的几种initrd的情况。

[kernel_init() -> populate_rootfs()]static int __init populate_rootfs(void){

/* 如果__initramfs_end - __initramfs_start不为0,就说明这是和内核文件集成在一起的cpio的intrd。*/

char *err = unpack_to_rootfs(__initramfs_start, __initramfs_end - __initramfs_start, 0); if (err) panic(err);#ifdef CONFIG_BLK_DEV_INITRD

/* 如果initrd_start不为0,说明这是由bootloader加载的initrd,

* 那么需要进一步判断是cpio格式的initrd,还是老式块设备的initrd。*/

if (initrd_start) {

#ifdef CONFIG_BLK_DEV_RAM int fd;

/* 首先判断是不是cpio格式的initrd,也就是这里说的initramfs。*/

printk(KERN_INFO "checking if image is initramfs...");

/* 这里unpack_to_rootfs()的最后一个参数为1,表示check only,不会执行解压缩。*/

err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start, 1);

if (!err) {

/* 如果是cpio格式的initrd,把它解压到前面挂载的根文件系统上,然后释放initrd占用的内存。*/ printk(" it is/n");

unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start, 0);

free_initrd();

return 0; }

/* 如果执行到这里,说明这是旧的块设备格式的initrd。

* 那么首先在前面挂载的根目录上创建一个initrd.image文件,

* 再把initrd_start到initrd_end的内容写入到/initrd.image中,

* 最后释放initrd占用的内存空间(它的副本已经保存到/initrd.image中了。)。

*/

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

}

......

return 0;}

rootfs_initcall(populate_rootfs);

经过populate_rootfs()函数的处理之后,如果是cpio格式的initrd,那么unpack_to_rootfs()函数已经把目录解压缩到之前mount的根目录上面了。但是如果是旧的块设备的initrd,unpack_to_rootfs()函数解压缩后得到的是一个块虚拟的设备镜像文件/initrd.image,对于这种情况,还需要进一步处理才能使用。接下来,kernel_init()就要处理这种情况。

static int __init kernel_init(void * unused){

......

do_basic_setup();

/* 内核启动时,可以通过启动参数rdinit=xxx 来指定启动的最后阶段,需要运行initrd中的哪一个可执行文件,

* 如果指定了这个参数,那么ramdisk_execute_command就会指向xxx这字符串,新cpio格式的initrd默认执行/init。

* 因此,如果如果ramdisk_execute_command为NULL,就把它设置为/init。*/

if (!ramdisk_execute_command)

ramdisk_execute_command = "/init";

/* 现在,尝试访问ramdisk_execute_command,默认为/init,如果访问失败,说明根目录上不存在这个文件。

* 于是调用prepare_namespace(),进一步检查是不是旧的块设备的initrd

* (在这种情况下,还是一个块设备镜像文件/initrd.image,所以访问/init文件失败。)。*/

if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {

ramdisk_execute_command = NULL;

prepare_namespace();

}

init_post();

return 0;}老式的initrd的处理

prepare_namespace()用于处理老式的initrd。

[kernel_init() -> prepare_namespace() -> initrd_load()]int __init initrd_load(void){

if (mount_initrd) {

create_dev("/dev/ram", Root_RAM0);

if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) {

sys_unlink("/initrd.image");

handle_initrd();

return 1;

}

}

sys_unlink("/initrd.image");

return 0;}

initrd_load()执行以下步骤:

调用create_dev()建立设备文件节点/dev/ram,其实这也是一个ramfs文件系统。

调用rd_load_image()把/initrd.image加载到/dev/ram中。

调用handle_initrd()把把块设备文件/dev/ram挂载到/root。

其中handle_initrd()代码如下:

[kernel_init() -> prepare_namespace() -> initrd_load() -> handle_initrd()]static void __init handle_initrd(void){

......

real_root_dev = new_encode_dev(ROOT_DEV);

/* 建立/dev/root.old设备文件。*/

create_dev("/dev/root.old", Root_RAM0);

/* 把/dev/root.old mount到/root目录。*/

/* 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);

/* chroot到/root目录,好了,现在/root目录成为当前的根目录。*/

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;

/* 建立一个线程,执行/linuxrc,这是旧的initrd默认执行的文件。*/

pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);

......

}

cpio格式的initrd的处理

对于新的cpio格式的initrd不需要额外的处理,因此kernel_init()继续执行:[kernel_init() -> init_post()]static int noinline init_post(void){

......

/* 打开console,注意如果cpio格式的根目录中不存在/dev/console文件,

* 在unpack_to_rootfs()函数也会建立这个设备文件。*/

if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)

printk(KERN_WARNING "Warning: unable to open an initial console./n");

/* 现在,标准输入,标准输出和标准错误全部都是/dev/console。*/

(void) sys_dup(0);

(void) sys_dup(0);

/* 执行ramdisk_execute_command指定的命令,默认为/init.*/

if (ramdisk_execute_command) {

run_init_process(ramdisk_execute_command);

printk(KERN_WARNING "Failed to execute %s/n", ramdisk_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.");}

在调用run_init_process()执行/init之后,这个函数就不会返回了,一般的发行版本的Linux中,initrd中的/init脚本会启动udevd,加载必要的设备驱动程序,然后挂载真正的根文件系统,最后在执行真正的根文件系统上的initrd,这样就这个启动过程就顺利的交接了。

块设备的initrd不仅使用不方便,而且在内核中的处理过程也更加复杂,因此cpio的initrd 肯定会取代它,推荐使用cpio格式的initrd.

initrd实例分析

如果您使用的是ubuntu,您可以执行以下的命令来看看它的initrd中的内容。

# mkdir /tmp/initrd

# cp /boot/initrd.img-xxx /tmp/initrd/initrd.img.gz

# cd /tmp/initrd# gunzip initrd.img.gz

# cat initrd.img | cpio -ivmd

现在,可以来看看这个根目录的init脚本到底做了什么。

# cat init

#!/bin/sh

# ubuntu

用户一定很熟悉这个消息。

echo "Loading, please wait..."......exec run-init ${rootmnt} ${init} "$@"

<${rootmnt}/dev/console >${rootmnt}/dev/console 2>&1

这个init脚本最后执行initrd中的run-init切换到真正的根文件系统中。

您可以对这个脚本进行修改,加入相关的打印信息,然后使用本文开头介绍的方法,重新制作一个cpio的initrd,然后使用这个initrd启动内核,快看看试验效果吧。

linux内核升级图文攻略

linux内核升级图文攻略 一、Linux内核概览Linux是一个一体化内核(monolithic kernel)系统。设备驱动程序可以完全访问硬件。Linux内的设备驱动程序可以方便地以模块化(modularize)的形式设置,并在系统运行期间可直接装载或卸载。1. linux内核linux 操作系统是一个用来和硬件打交道并为用户程序提供一个 有限服务集的低级支撑软件。一个计算机系统是一个硬件和软件的共生体,它们互相依赖,不可分割。计算机的硬件,含有外围设备、处理器、内存、硬盘和其他的电子设备组成计算机的发动机。但是没有软件来操作和控制它,自身是不能工作的。完成这个控制工作的软件就称为操作系统,在Linux的术语中被称为“内核”,也可以称为“核心”。Linux内核的主要模块(或组件)分以下几个部分:. 进程管理(process management) . 定时器(timer). 中断管理(interrupt management). 内存管理(memory management). 模块管理(module management). 虚拟文件系统接口(VFS layer). 文件系统(file system). 设备驱动程序(device driver). 进程间通信(inter-process communication). 网络管理(network management. 系统启动(system init)等操作系统功能的实现。2. linux内核版本号Linux内核使用三种不同的版本编号方式。. 第一种方

式用于1.0版本之前(包括1.0)。第一个版本是0.01,紧接着是0.02、0.03、0.10、0.11、0.12、0.95、0.96、0.97、0.98、0.99和之后的1.0。. 第二种方式用于1.0之后到2.6,数字由三部分“A.B.C”,A代表主版本号,B代表次主版本号,C代表较小的末版本号。只有在内核发生很大变化时(历史上只发生过两次,1994年的1.0,1996年的2.0),A才变化。可以通过数字B来判断Linux是否稳定,偶数的B代表稳定版,奇数的B代表开发版。C代表一些bug修复,安全更新,新特性和驱动的次数。以版本2.4.0为例,2代表主版本号,4代表次版本号,0代表改动较小的末版本号。在版本号中,序号的第二位为偶数的版本表明这是一个可以使用的稳定版本,如2.2.5; 而序号的第二位为奇数的版本一般有一些新的东西加入,是个不一定很稳定的测试版本,如2.3.1。这样稳定版本来源于上一个测试版升级版本号,而一个稳定版本发展到完全成熟后就不再发展。. 第三种方式从2004年2.6.0版本开始,使用一种“time-based”的方式。 3.0版本之前,是一种“A.B.C.D”的格式。七年里,前两个数字A.B即“2.6”保持不变,C随着新版本的发布而增加,D代表一些bug修复,安全更新,添加新特性和驱动的次数。3.0版本之后是“A.B.C”格式,B随着新版本的发布而增加,C代表一些bug修复,安全更新,新特性和驱动的次数。第三种方式中不使用偶数代表稳定版,奇数代表开发版这样的命名

探究linux内核,超详细解析子系统

探究linux内核,超详细解析子系统 Perface 前面已经写过一篇《嵌入式linux内核的五个子系统》,概括性比较强,也比较简略,现在对其进行补充说明。 仅留此笔记,待日后查看及补充!Linux内核的子系统 内核是操作系统的核心。Linux内核提供很多基本功能,如虚拟内存、多任务、共享库、需求加载、共享写时拷贝(Copy-On-Write)以及网络功能等。增加各种不同功能导致内核代码不断增加。 Linux内核把不同功能分成不同的子系统的方法,通过一种整体的结构把各种功能集合在一起,提高了工作效率。同时还提供动态加载模块的方式,为动态修改内核功能提供了灵活性。系统调用接口用户程序通过软件中断后,调用系统内核提供的功能,这个在用户空间和内核提供的服务之间的接口称为系统调用。系统调用是Linux内核提供的,用户空间无法直接使用系统调用。在用户进程使用系统调用必须跨越应用程序和内核的界限。Linux内核向用户提供了统一的系统调用接口,但是在不同处理器上系统调用的方法

各不相同。Linux内核提供了大量的系统调用,现在从系统 调用的基本原理出发探究Linux系统调用的方法。这是在一个用户进程中通过GNU C库进行的系统调用示意图,系 统调用通过同一个入口点传入内核。以i386体系结构为例,约定使用EAX寄存器标记系统调用。 当加载了系统C库调用的索引和参数时,就会调用0x80软件中断,它将执行system_call函数,这个函数按照EAX 寄存器内容的标示处理所有的系统调用。经过几个单元测试,会使用EAX寄存器的内容的索引查system_call_table表得到系统调用的入口,然后执行系统调用。从系统调用返回后,最终执行system_exit,并调用resume_userspace函数返回用户空间。 linux内核系统调用的核心是系统多路分解表。最终通过EAX寄存器的系统调用标识和索引值从对应的系统调用表 中查出对应系统调用的入口地址,然后执行系统调用。 linux系统调用并不单层的调用关系,有的系统调用会由

Linux kernel内核升级全过程,教你一次成功

序言 由于开发环境需要在linux-2.6内核上进行,于是准备对我的虚拟机上的Linux系统升级。没想到这一弄就花了两天时间( 反复装系统,辛苦啊~~),总算把Linux系统从2.4.20-8内核成功升级到了2.6.18内核。 网上虽然有很多介绍Linux内核升级的文章,不过要么过时,下载链接失效;要么表达不清,不知所云;更可气的是很多 文章在转载过程中命令行都有错误。刚开始我就是在这些“攻略”的指点下来升级的,以致于浪费了很多时间。 现在,费尽周折,升级成功,心情很爽,趁性也来写个“升级攻略”吧!于是特意又在虚拟机上重新安装一个Linux系统 ,再来一次完美的升级,边升级边记录这些步骤,写成一篇Linux内核升级记实录(可不是回忆录啊!),和大家一起分享 ~~! 一、准备工作 首先说明,下面带#号的行都是要输入的命令行,且本文提到的所有命令行都在终端里输入。 启动Linux系统,并用根用户登录,进入终端模式下。 1、查看Linux内核版本 # uname -a 如果屏幕显示的是2.6.x,说明你的已经是2.6的内核,也用不着看下文了,该干什么干什么去吧!~~~如果显示的是 2.4.x,那恭喜你,闯关通过,赶快进行下一步。 2、下载2.6内核源码 下载地址:https://www.wendangku.net/doc/fb18534278.html,/pub/linux/kernel/v2.6/linux-2.6.18.tar.bz2 3、下载内核升级工具 (1)下载module-init-tools-3.2.tar.bz2 https://www.wendangku.net/doc/fb18534278.html,/pub/linux/utils/kernel/module-init-tools/module-init-tools-3.2.tar.bz2 (2)下载mkinitrd-4.1.18-2.i386.rpm https://www.wendangku.net/doc/fb18534278.html,/fedora/linux/3/i386/RPMS.core/mkinitrd-4.1.18-2.i386.rpm (3)下载lvm2-2.00.25-1.01.i386.rpm https://www.wendangku.net/doc/fb18534278.html,/fedora/linux/3/i386/RPMS.core/lvm2-2.00.25-1.01.i386.rpm (4)下载device-mapper-1.00.19-2.i386.rpm https://www.wendangku.net/doc/fb18534278.html,/fedora/linux/3/i386/RPMS.core/device-mapper-1.00.19-2.i386.rpm (2.6.18内核和这4个升级工具我都有备份,如果以上下载地址失效,请到https://www.wendangku.net/doc/fb18534278.html,/guestbook留下你的邮箱,我给你发过去)

关于Linux 内核中五个主要子系统的介绍

关于Linux 内核中五个主要子系统的介绍 发布时间:2008.01.02 06:23来源:赛迪网作者:sixth 1.进程调度(SCHED):控制进程对CPU的访问。当需要选择下一个进程运行时,由调度程序选择最值得运行的进程。可运行进程实际上是仅等待CPU资源的进程,如果某个进程在等待其它资源,则该进程是不可运行进程。Linux使用了比较简单的基于优先级的进程调度算法选择新的进程。 2.内存管理(MM)允许多个进程安全的共享主内存区域。Linux的内存管理支持虚拟内存,即在计算机中运行的程序,其代码,数据,堆栈的总量可以超过实际内存的大小,操作系统只是把当前使用的程序块保留在内存中,其余的程序块则保留在磁盘中。必要时,操作系统负责在磁盘和内存间交换程序块。内存管理从逻辑上分为硬件无关部分和硬件有关部分。硬件无关部分提供了进程的映射和逻辑内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。 3.虚拟文件系统(VirtualFileSystem,VFS)隐藏了各种硬件的具体细节,为所有的设备提供了统一的接口,VFS提供了多达数十种不同的文件系统。虚拟文件系统可以分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2,fat等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。 4.网络接口(NET)提供了对各种网络标准的存取和各种网络硬件的支持。网络接口可分为网络协议和网络驱动程序。网络协议部分负责实现每一种可能的网络传输协议。网络设备驱动程序负责与硬件设备通讯,每一种可能的硬件设备都有相应的设备驱动程序。 5.进程间通讯(IPC) 支持进程间各种通信机制。处于中心位置的进程调度,所有其它的子系统都依赖它,因为每个子系统都需要挂起或恢复进程。一般情况下,当一个进程等待硬件操作完成时,它被挂起;当操作真正完成时,进程被恢复执行。例如,当一个进程通过网络发送一条消息时,网络接口需要挂起发送进程,直到硬件成功地完成消息的发送,当消息被成功的发送出去以后,网络接口给进程返回一个代码,表示操作的成功或失败。其他子系统以相似的理由依赖于进程调度。

linux内核IMQ源码实现分析

本文档的Copyleft归wwwlkk所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性,严禁用于任何商业用途。 E-mail: wwwlkk@https://www.wendangku.net/doc/fb18534278.html, 来源: https://www.wendangku.net/doc/fb18534278.html,/?business&aid=6&un=wwwlkk#7 linux2.6.35内核IMQ源码实现分析 (1)数据包截留并重新注入协议栈技术 (1) (2)及时处理数据包技术 (2) (3)IMQ设备数据包重新注入协议栈流程 (4) (4)IMQ截留数据包流程 (4) (5)IMQ在软中断中及时将数据包重新注入协议栈 (7) (6)结束语 (9) 前言:IMQ用于入口流量整形和全局的流量控制,IMQ的配置是很简单的,但很少人分析过IMQ的内核实现,网络上也没有IMQ的源码分析文档,为了搞清楚IMQ的性能,稳定性,以及借鉴IMQ的技术,本文分析了IMQ的内核实现机制。 首先揭示IMQ的核心技术: 1.如何从协议栈中截留数据包,并能把数据包重新注入协议栈。 2.如何做到及时的将数据包重新注入协议栈。 实际上linux的标准内核已经解决了以上2个技术难点,第1个技术可以在NF_QUEUE机制中看到,第二个技术可以在发包软中断中看到。下面先介绍这2个技术。 (1)数据包截留并重新注入协议栈技术

(2)及时处理数据包技术 QoS有个技术难点:将数据包入队,然后发送队列中合适的数据包,那么如何做到队列中的数

激活状态的队列是否能保证队列中的数据包被及时的发送吗?接下来看一下,激活状态的队列的 证了数据包会被及时的发送。 这是linux内核发送软中断的机制,IMQ就是利用了这个机制,不同点在于:正常的发送队列是将数据包发送给网卡驱动,而IMQ队列是将数据包发送给okfn函数。

ubuntu12.04 升级内核实战

ubuntu12.04 升级内核实战 ubuntu 12.04内核是linux 3.2.0-24,其实升级到最新版本3.3.4也没什么很大意义,主要是集成了一些新的驱动和一些普通用户用不到的功能,所以基本上本文纯属折腾,但不要随便升级当班设备啊!好了,不废话了,我们开始........... 首先是准备条件: ①、有一台装有ubuntu 12.04的机器 ②、先移步到https://www.wendangku.net/doc/fb18534278.html,/下载linux稳定版内核 ③、拥有root权限 ④、并将下载好的内核解压到/usr/src下,使用命令如下: #tar jxvf linux-3.3.4.tar.bz2 这样你就可以得到一个名叫linux-3.3.4 好,现在一切都准备好了,接下来就开始配置,编译,安装新内核吧!1,进入刚才的文件夹/usr/src/linux-3.3.4,输入命令:$ make mrproper 该命令的功能在于清除当前目录下残留的.config和.o文件,这些文件一般是以前编译时未清理而残留的。而对于第一次编译的代码来说,不存在这些残留文件,所以可以略过此步,但是如果该源代码以前被编译过,那么强烈建议执行此命令,否则后面可能会出现未知的问题。2,配置编译选项 作为操作系统的内核,其内容和功能必然非常繁杂,包括处理器调

度,内存管理,文件系统管理,进程通讯以及设备管理等等,而对于不同的硬件,其配置选项也不相同,所以在编译源代码之前必须设置编译选项。其实我觉得这一步是升级内核整个过程中最有技术含量的,因为要根据自己的需要正确选择yes or no需要对计算机方方面面的知识都有所了解。但是这里的选项实在是太多了,大概有几百项之多,我以前曾尝试着一项一项的选,但是最后还是放弃了,因为有很多选项不是很明白。 既然这样,难道没有什么简便的方法么?当然有!那就是make menuconfig 或者make xconfig。我使用的是make menuconfig,但是前提条件是要装ncurses。 ncurses 到https://www.wendangku.net/doc/fb18534278.html,/pub/gnu/ncurses/下载,可以放到任何目录进行安装: tar zxvf ncurses.tar.gz #解压缩并且释放文件包 cd ncurses #进入解压缩的目录(注意版本) ./configure #按照你的系统环境制作安装配置文件 make #编译源代码并且编译NCURSES库 su root #切换到root用户环境 make install #安装编译好的NCURSES库 另外,在make menuconfig过程中也会有一些选项需要你来设置

Linux内核结构详解教程

Linux内核结构详解教程 ─────Linux内核教程 linux内核就像人的心脏,灵魂,指挥中心。 内核是一个操作系统的核心,它负责管理系统的进程,内存,设备驱动程序,文件和网络系统,决定着系统的性能和稳定性。内核以独占的方式执行最底层任务,保证系统正常运行。协调多个并发进程,管理进程使用的内存,使它们相互之间不产生冲突,满足进程访问磁盘的请求等等. 严格说Linux并不能称做一个完整的操作系统.我们安装时通常所说的Linux,是有很多集合组成的.应称为GNU/Linux. 一个Linux内核很少1.2M左右,一张软盘就能放下. 内容基础,语言简短简洁 红联Linux论坛是致力于Linux技术讨论的站点,目前网站收录的文章及教程基本能满足不同水平的朋友学习。 红联Linux门户: https://www.wendangku.net/doc/fb18534278.html, 红联Linux论坛: https://www.wendangku.net/doc/fb18534278.html,/bbs 红联Linux 论坛大全,所有致力点都体现在这 https://www.wendangku.net/doc/fb18534278.html,/bbs/rf/linux/07.htm

目录 Linux内核结构详解 Linux内核主要五个子系统详解 各个子系统之间的依赖关系 系统数据结构 Linux的具体结构 Linux内核源代码 Linux 内核源代码的结构 从何处开始阅读源代码 海量Linux技术文章

Linux内核结构详解 发布时间:2006-11-16 19:05:29 Linux内核主要由五个子系统组成:进程调度,内存管理,虚拟文件系统,网络接口,进程间通信。

Linux内核主要五个子系统详解 发布时间:2006-11-16 19:05:54 1.进程调度(SCHED):控制进程对CPU的访问。当需要选择下一个进程运行时,由调度程序选择最值得运行的进程。可运行进程实际上是仅等待CPU资源的进程,如果某个进程在等待其它资源,则该进程是不可运行进程。Linux使用了比较简单的基于优先级的进程调度算法选择新的进程。 2.内存管理(MM)允许多个进程安全的共享主内存区域。Linux的内存管理支持虚拟内存,即在计算机中运行的程序,其代码,数据,堆栈的总量可以超过实际内存的大小,操作系统只是把当前使用的程序块保留在内存中,其余的程序块则保留在磁盘中。必要时,操作系统负责在磁盘和内存间交换程序块。内存管理从逻辑上分为硬件无关部分和硬件有关部分。硬件无关部分提供了进程的映射和逻辑内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。 3.虚拟文件系统(VirtualFileSystem,VFS)隐藏了各种硬件的具体细节,为所有的设备提供了统一的接口,VFS提供了多达数十种不同的文件系统。虚拟文件系统可以分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2,fat等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。 4.网络接口(NET)提供了对各种网络标准的存取和各种网络硬件的支持。网络接口可分为网络协议和网络驱动程序。网络协议部分负责实现每一种可能的网络传输协议。网络设备驱动程序负责与硬件设备通讯,每一种可能的硬件设备都有相应的设备驱动程序。 5.进程间通讯(IPC) 支持进程间各种通信机制。 处于中心位置的进程调度,所有其它的子系统都依赖它,因为每个子系统都需要挂起或恢复进程。一般情况下,当一个进程等待硬件操作完成时,它被挂起;当操作真正完成时,进程被恢复执行。例如,当一个进程通过网络发送一条消息时,网络接口需要挂起发送进程,直到硬件成功地完成消息的发送,当消息被成功的发送出去以后,网络接口给进程返回一个代码,表示操作的成功或失败。其他子系统以相似的理由依赖于进程调度。

redhat5.8升级内核版本培训资料

r e d h a t5.8升级内核 版本

一、升级背景 前段时间公司有个项目用到了短信收发的业务,采购了两台16口的Wavecom USB短信猫设备,服务器操作系统是ReadHat5.4,内核2.6.18,插上设备后,操作系统无法自动识别该设备,原因是没有预装该设备USB转串口的驱动程序,可能是只有这个产品不能识别,因为曾经我用过单口的GSM MODEM短信猫测试,可以自动识别出来。后来从供应商处得到信息,说是他们这个产品比较新,版本低的内核没有预装新的USB转串口驱动程序,但现在2.6.32以上内核都自带了USB转串口的驱动,所以最后通过升级系统内核的方式解决了这个问题。 二、升级测试环境 宿主机:Window xp 虚拟机:VM8.0.2 OS:CentOS 5.8 Final 内核(升级前):2.6.18 所有操作步聚使用root权限 三、升级步聚 1、下载内核 到https://www.wendangku.net/doc/fb18534278.html,下载一个新版本内核源码,当前最新稳定版为3.3.4。这里下载的是: https://www.wendangku.net/doc/fb18534278.html,/pub/linux/kernel/v2.6/longterm/v2.6.35/linux-2.6.35.13.tar.bz2

2、解压内核文件 将linux-2.6.35.13.tar.bz2上传到/usr/local/src目录下,使用tar -jxvf linux-2.6.35.13.tar.bz2命令解压,得到linux-2.6.35.13目录 3、清除文件 cd linux-2.6.35.13(下面所有操作都是在此目录,除非切换了新的目录) make distclean 清除以前编译内核生成的所有文件(除了清除可执行文件和目标文件外,configure所产生的Makefile也会清除掉) 如果是第一次编译,这步聚可以省略 4、复制配置文件 将系统默认的内核配置文件复制到linux-2.6.35.13目录下,并命名.config cp /boot/config-2.6.18-308.el5 .config 5、内核配置(make menuconfig) 内核配置,有三种方式: a)、make config:基于文本的最为传统的配置界面,不推荐使用 b)、make menuconfig:基于文本选单的配置界面,字符终端下推荐使用。 注意:使用make menuconfig 需要安装ncurses(yum -y install ncurses-devel),如果未安装会报如下错误:

RedHat5 内核升级指南

RedHat5.3 升级内核到2.6.33 版本

错误:insmod: error inserting '/lib/dm-region-hash.ko' : -1 File exists 编译2.6.31内核后重启出现 insmod: error inserting '/lib/dm-region-hash.ko' : -1 File exists 解决方法: 1,解压initrd文件 [root@bogon ~]# cp /boot/initrd-2.6.30.4.img /tmp [root@bogon ~]# cd /tmp/ [root@bogon tmp]# ls initrd-2.6.30.4.img [root@bogon tmp]# mkdir newinitrd [root@bogon tmp]# cd newinitrd/ [root@bogon newinitrd]# zcat ../initrd-2.6.30.4.img |cpio -i 11537 blocks 释放之后看到如下内容 [root@bogon newinitrd]# ls bin dev etc init lib proc sbin sys sysroot 2,ok,下边就是编辑init,删掉其中重复的四行中的两行 echo "Loading dm-region-hash.ko module" insmod /lib/dm-region-hash.ko echo "Loading dm-region-hash.ko module" insmod /lib/dm-region-hash.ko 3,重新打包initrd [root@bogon newinitrd]# find .|cpio -c -o > ../initrd 11538 blocks [root@bogon newinitrd]# cd .. [root@bogon tmp]# gzip -9 < initrd > initrd.img [root@bogon tmp]# ls initrd-2.6.30.4.img initrd initrd.img newinitrd 好了,initrd.img就是重新打包的initrd了,然后把initrd.img拷贝到/boot,更改grub.conf里边的initrd-2.6.30.4.img为initrd.img就可以了, 这样“insmod: error inserting '/lib/dm-region-hash.ko' : -1 File exists”就不会有了 其实将init文件的第二行“setquiet”去掉,你就知道initrd文件到底在做什么了

Linux内核分析-网络[五]:网桥

看完了路由表,重新回到netif_receive_skb ()函数,在提交给上层协议处理前,会执行下面一句,这就是网桥的相关操作,也是这篇要讲解的容。 view plaincopy to clipboardprint? 1. s kb = handle_bridge(skb, &pt_prev, &ret, orig_dev); 网桥可以简单理解为交换机,以下图为例,一台linux机器可以看作网桥和路由的结合,网桥将物理上的两个局域网LAN1、LAN2当作一个局域网处理,路由连接了两个子网1.0和2.0。从eth0和eth1网卡收到的报文在Bridge模块中会被处理成是由Bridge收到的,因此Bridge也相当于一个虚拟网卡。 STP五种状态 DISABLED BLOCKING LISTENING LEARNING FORWARDING 创建新的网桥br_add_bridge [net\bridge\br_if.c] 当使用SIOCBRADDBR调用ioctl时,会创建新的网桥br_add_bridge。 首先是创建新的网桥: view plaincopy to clipboardprint?

1. d ev = new_bridge_dev(net, name); 然后设置dev->dev.type为br_type,而br_type是个全局变量,只初始化了一个名字变量 view plaincopy to clipboardprint? 1. S ET_NETDEV_DEVTYPE(dev, &br_type); 2. s tatic struct device_type br_type = { 3. .name = "bridge", 4. }; 然后注册新创建的设备dev,网桥就相当一个虚拟网卡设备,注册过的设备用ifconfig 就可查看到: view plaincopy to clipboardprint? 1. r et = register_netdevice(dev); 最后在sysfs文件系统中也创建相应项,便于查看和管理: view plaincopy to clipboardprint? 1. r et = br_sysfs_addbr(dev); 将端口加入网桥br_add_if() [net\bridge\br_if.c] 当使用SIOCBRADDIF调用ioctl时,会向网卡加入新的端口br_add_if。 创建新的net_bridge_port p,会从br->port_list中分配一个未用的port_no,p->br会指向br,p->state设为BR_STATE_DISABLED。这里的p实际代表的就是网卡设备。 view plaincopy to clipboardprint? 1. p = new_nbp(br, dev); 将新创建的p加入CAM表中,CAM表是用来记录mac地址与物理端口的对应关系;而刚刚创建了p,因此也要加入CAM表中,并且该表项应是local的[关系如下图],可以看到,CAM表在实现中作为net_bridge的hash表,以addr作为hash值,链入 net_bridge_fdb_entry,再由它的dst指向net_bridge_port。

Linux如何禁止系统内核Kernel自动升级

Linux如何禁止系统内核Kernel自动升级 Kernel是系统内核,Linux系统在进行升级的时候内核也会跟着更新,有时为了避免不必要的麻烦,不少用户会选择不升级Linux内核,那么要如何禁止Kernel升级呢? 不过在更新其他软件包时,如果依赖最新的内核,那么该软件包是没法更新成功的。 方法如下: 方法1: # vim /etc/yum.conf exclude=kernel* 在 [main]配置段下,追加或修改以上内容。 可通过下面的命令查看是否生效: # yum update | grep -i kernel 方法2: 在yum命令行中加上-x参数,来跳过指定的更新。如: # yum -x ‘kernel*’ update Linux禁止系统内核Kernel升级的方法就介绍到这里了,方法2是通过在yum命令行中加入参数来实现的,相较于方法1简单了很多。 【拓展阅读】Linux 新手容易犯的 7 个错误 7. 选择错误的 Linux 发行版 Linux 有几百个不同的版本,或者按他们的称呼叫做发行版(distribution)。其中许多是专门针对不同的版本或用户的。选择了错误的版本,你与 Linux 的第一次亲密体验将很快变成一个噩梦。 如果你是在朋友的帮助下切换的话,确认他们的建议是适合你,而不是他们。有大量的文章可以帮助到你,你只需要关注前 20 名左右的或者列在 Distrowatch 的即可,就不太可能会搞错。

更好的做法是,在你安装某个发行版之前先试试它的 Live DVD。Live DVD 是在外设 上运行发行版的,这样可以允许你在不对硬盘做任何改动的情况下对其进行测试。事实上,除非你知道怎么让硬盘在 Linux 下可访问,否则你是不会看到你的硬盘的。 6. 期待什么都是一样的 由于经验有限,许多 Windows 用户不知道新的意味着新的程序和新的处理方式。事 实上你的 Windows 程序是无法在 Linux 上运行的,除非你用 WINE 或者 Windows 虚拟机。而且你还不能用 MS Office 或者 PhotoShop ——你必须要学会使用 LibreOffice 和 Krita。 经过这些年,这些应用可能会有和 Windows 上的应用类似的功能,但它们的功能可能具 有不同的名称,并且会从不同的菜单或工具栏获得。 就连很多想当然的都不一样了。Windows 用户会特别容易因为他们有多个桌面环境 可以选择而大吃一惊——至少有一个主要的和很多次要的桌面环境。 5. 安装软件的时候不知所措 在 Windows 上,新软件是作为一个完全独立的程序来安装的。通常它囊括了其它所 需的依赖库。 有两种叫做 Flatpak 和 Snap 的软件包服务目前正在 Linux 上引进类似的安装系统, 但是它们对于移动设备和嵌入式设备来说太大了。更多情况下,Linux 依赖于包管理系统,它会根据已安装的包来判断软件的依赖包是否是必需的,从而提供其它所需的依赖包。 笔记本和工作站上的包管理本质上相当于手机或平板电脑上的 Google Play:它速度 很快,并且不需要用于安装的物理介质。不仅如此,它还可以节省 20%-35% 的硬盘空间,因为依赖包不会重复安装。 4. 假想软件会自动更新好 Linux 用户认为控制权很重要。Linux 提供更新服务,不过默认需要用户手动运行。 例如,大多数发行版会让你知道有可用的软件更新,但是你需要选择安装这些更新。 如果你选择更新的话,你甚至可以单独决定每一个更新。例如,你可能不想更新到新的内核,因为你安装了一些东西需要使用当前的内核。又或者你想要安装所有的安全性更新,但不想把发行版更新到一个新的版本。一切都由你来选择。 3. 忘记密码 许多 Windows 用户因为登录不方便而忘记密码。又或者为了方便起见,经常运行一 个管理账户。

史上最全linux内核配置详解

对于每一个配置选项,用户可以回答"y"、"m"或"n"。其中"y"表示将相应特性的支持或设备驱动程序编译进内核;"m"表示将相应特性的支持或设备驱动程序编译成可加载模块,在需要时,可由系统或用户自行加入到内核中去;"n"表示内核不提供相应特性或驱动程序的支持。只有<>才能选择M 1. General setup(通用选项) [*]Prompt for development and/or incomplete code/drivers,设置界面中显示还在开发或者还没有完成的代码与驱动,最好选上,许多设备都需要它才能配置。 [ ]Cross-compiler tool prefix,交叉编译工具前缀,如果你要使用交叉编译工具的话输入相关前缀。默认不使用。嵌入式linux更不需要。 [ ]Local version - append to kernel release,自定义版本,也就是uname -r可以看到的版本,可以自行修改,没多大意义。 [ ]Automatically append version information to the version string,自动生成版本信息。这个选项会自动探测你的内核并且生成相应的版本,使之不会和原先的重复。这需要Perl的支持。由于在编译的命令make-kpkg 中我们会加入- –append-to-version 选项来生成自定义版本,所以这里选N。 Kernel compression mode (LZMA),选择压缩方式。 [ ]Support for paging of anonymous memory (swap),交换分区支持,也就是虚拟内存支持,嵌入式不需要。 [*]System V IPC,为进程提供通信机制,这将使系统中各进程间有交换信息与保持同步的能力。有些程序只有在选Y的情况下才能运行,所以不用考虑,这里一定要选。 [*]POSIX Message Queues,这是POSIX的消息队列,它同样是一种IPC(进程间通讯)。建议你最好将它选上。 [*]BSD Process Accounting,允许进程访问内核,将账户信息写入文件中,主要包括进程的创建时间/创建者/内存占用等信息。可以选上,无所谓。 [*]BSD Process Accounting version 3 file format,选用的话统计信息将会以新的格式(V3)写入,注意这个格式和以前的v0/v1/v2 格式不兼容,选不选无所谓。 [ ]Export task/process statistics through netlink (EXPERIMENTAL),通过通用的网络输出工作/进程的相应数据,和BSD不同的是,这些数据在进程运行的时候就可以通过相关命令访问。和BSD类似,数据将在进程结束时送入用户空间。如果不清楚,选N(实验阶段功能,下同)。 [ ]Auditing support,审计功能,某些内核模块需要它(SELINUX),如果不知道,不用选。 [ ]RCU Subsystem,一个高性能的锁机制RCU 子系统,不懂不了解,按默认就行。 [ ]Kernel .config support,将.config配置信息保存在内核中,选上它及它的子项使得其它用户能从/proc/ config.gz中得到内核的配置,选上,重新配置内核时可以利用已有配置Enable access to .config through /proc/config.gz,上一项的子项,可以通过/proc/ config.gz访问.config配置,上一个选的话,建议选上。 (16)Kernel log buffer size (16 => 64KB, 17 => 128KB) ,内核日志缓存的大小,使用默认值即可。12 => 4 KB,13 => 8 KB,14 => 16 KB单处理器,15 => 32 KB多处理器,16 => 64 KB,17 => 128 KB。 [ ]Control Group support(有子项),使用默认即可,不清楚可以不选。 Example debug cgroup subsystem,cgroup子系统调试例子 Namespace cgroup subsystem,cgroup子系统命名空间 Device controller for cgroups,cgroups设备控制器

ubuntu内核升级及卸载

ubuntu内核升级及卸载 ubuntu下内核的升级与卸载 很多用户一般都会选择Windows + Ubuntu的双系统。用得时间久了,随着Ubuntu内核的不断升级,开机启动菜单会变得越来越臃肿。下面简单介绍一下如何删除开机启动菜单多余的内核(旧版本),以及如何调整不同操作系统的启动顺序。 Ubuntu是由grub引导启动的。每当Ubuntu升级到新的版本后,grub会自动调整开机启动菜单的顺序,把新的内核放在启动菜单的开始,同时也不会删除久的内核版本。这样,当Ubuntu的升级次数一多,启动菜单中将变得非常臃肿。而且那些旧版本的内核基本不会用,不如删除之。解决方案如下: 1.找出系统已经安装的内核版本,在终端里输入命令:dpkg --get-selections | grep linux-image 然后会显示系统中已安装的内核,例如: linux-image-2.6.35-22-generic install linux-image-2.6.38-10-generic install

linux-image-2.6.38-11-generic install linux-image-2.6.38-8-generic install linux-image-3.0.0-12-generic install linux-image-generic install 2.卸载旧的内核版本,在终端里输入命令:sudo apt-get remove linux-image-2.6.35-22-generic linux-image-2.6.38-8-generic linux-image-2.6.38-10-generic linux-image-2.6.38-11-generic 上面命令和含义是: dpkg --get-selections [ ...] 把已选中的软件包列表打印到标准输出; grep linux-image 匹配查找; uname -a 查看已安装的linux内核版。 这样,旧的内核版本就删除了。然而,grub修改开机启动菜单,会自动把最新的Ubuntu放在第一位,把Windows放在最后一个。我们经常希望把Windows调整到靠前的位置,可能还会修改默认的启动项和等待时间等。解决方案如下:1.找到grub配置,打开配置文档,在终端里输入命令:sudo gedit /boot/grub/grub.cfg 2.修改grub配置

实例解析linux内核I2C体系结构(2)

实例解析linux内核I2C体系结构(2) 华清远见刘洪涛四、在内核里写i2c设备驱动的两种方式 前文介绍了利用/dev/i2c-0在应用层完成对i2c设备的操作,但很多时候我们还是习惯为i2c设备在内核层编写驱动程序。目前内核支持两种编写i2c驱动程序的方式。下面分别介绍这两种方式的实现。这里分别称这两种方式为“Adapter方式(LEGACY)”和“Probe方式(new style)”。 (1)Adapter方式(LEGACY) (下面的实例代码是在2.6.27内核的pca953x.c基础上修改的,原始代码采用的是本文将要讨论的第2种方式,即Probe方式) ●构建i2c_driver static struct i2c_driver pca953x_driver = { .driver = { .name= "pca953x", //名称 }, .id= ID_PCA9555,//id号 .attach_adapter= pca953x_attach_adapter, //调用适配器连接设备 .detach_client= pca953x_detach_client,//让设备脱离适配器 }; ●注册i2c_driver static int __init pca953x_init(void) { return i2c_add_driver(&pca953x_driver); } module_init(pca953x_init); ●attach_adapter动作 执行i2c_add_driver(&pca953x_driver)后会,如果内核中已经注册了i2c适配器,则顺序调用这些适配器来连接我们的i2c设备。此过程是通过调用i2c_driver中的attach_adapter方法完成的。具体实现形式如下: static int pca953x_attach_adapter(struct i2c_adapter *adapter) { return i2c_probe(adapter, &addr_data, pca953x_detect); /* adapter:适配器 addr_data:地址信息 pca953x_detect:探测到设备后调用的函数 */ } 地址信息addr_data是由下面代码指定的。 /* Addresses to scan */ static unsigned short normal_i2c[] = {0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,I2C_CLIENT_END}; I2C_CLIENT_INSMOD;

[教程] (已更新6个AMD适用的内核)

这篇贴子是我依照samsonwtsui大大的一步神贴,补充了大大忽略的问题,删繁就简总结出来的产物,以供新手们作为安装雪豹系统的参考,我的是AMD的CPU,其它的U也适用(主要是替换内核部分不同),新手结合我的贴子和一步神贴阅读效果更佳! 第一步:缩小现有分区卷 雪豹使用自己的文件系统,HFS+,不兼容Windows的NTFS文件系统,这个指南需要2个HFS+分区完成安装任务,其中一个大小是6.3GB,用来放雪豹安装光盘,另一个用来放雪豹操作系统,大小是20GB(按照自己需要增减,操作系统本身就占了约4.5GB)。 操作: 1. 右键点击我的电脑(计算机)——>管理——>弹出来的窗口左边的磁盘管理,这里你可以看见你的硬盘分区状况。 2. 在D盘上点击右键——>压缩卷然后在弹出来的框输入26906(1024MB/GB×26.3GB),然后按确定即可。(XP用户和使用FAT32格式的用户如无法压缩卷可以使用Acronis Disk Director Suite或Paragon PM实现类似功能)

3. 右键点击未分配空间——>新建简单卷,点击下一步后输入6426(1024MB/GB×6.3GB),下一步将此空间分配到E,不要格式化。完成之后Windows会弹出框告诉你需要格式化E才能访问,先谢谢她的好意,不过选择取消,不格式化。 4. 用同样的办法把剩下的20G也新建一个卷。这个卷随便你格不格式化。 技巧:6.3GB的盘一定要靠近原来的D盘,等安装完成后把这个光盘拆了,用扩展卷功能又能够让它的空间合到D盘里面。 第二步:加载DVD到硬盘并修改。 1.下载HFS-Explorer并安装 2.若你的Windows之前没有安装Java VM(Java JRE虚拟机),也另需下载安装。 3.打开HFS-Explorer点击"File"—>"Load file system from file",在弹出框里找到雪豹的安装光盘DMG文件,然后在弹出框里选含有HFS+那一项,如图,然后点即可。已购买苹果DVD 的朋友插入光盘后点击"File"—>"Load file system from device",然后点击“Load”

相关文档