当前位置:Linux教程 - Linux - 内核FAQ(2001.05.26~2001.06.06)

内核FAQ(2001.05.26~2001.06.06)



         1、 mm/slab.c 文件的内容
    2、 怎样在内核中获得拦截文件的全路径
    3、 LKM编写初级问题
    4、 insmod可卸载内核问题
    5、 关于bootsect.S的一个问题

    1、mm/slab.c 文件是关于存储管理的某一方面,如果能简要分析一下内容的话,在下感激不尽!!

    Slab Allocator分配算法的实现基于对象缓存机制,其使用的的对象复用技术比传统的分配内存块方式优越。该算法基于这样一个事实:有一部分内核数据结构由于经常被使用,所以它们可以经常被复用。因此该算法为这些经常使用的内核数据结构分配内存,并将它们视为对象进行统一管理,对象被创建并使用完毕后,并不是立即把对象释放,而是暂时保留,当对相同的对象又有新的要求时就可以立即使用被保留的对象,这样就可以省去很多的内核内存分配和回收操作,减轻了内核的工作负担。

    另外,Slab Allocator分配算法的可以控制被分配的内存的粒度,可以对特定的数据结构进行度身订造,大大减少了内存的浪费。该算法腥闶莩橄螅夯捍?kmem_cache_t),Slab(kmem_slab_t),对象(kmem_bufctl_s)。缓存集中管理Slab,Slab集中管理对象。每个捍胬锩嬗卸喔鯯lab,而每个Slab中的则含有多个相同类型的对象。Cache有两种类型:通用cache和专用cache。通用cache仅被slab分配器用于本身的特定目的,而专用cache则用于内核的剩下部分用途。通用cache由kmem_cache_init()和kmem_cache_sizes_init() 在内核初始化时建立。专用cache则由kmem_cache_create()函数创建。通用cache中,第一个cache名为cache_cache,里面的内容为专用cache的描述符。第二个cache名为cache_slabp,里面的内容是那些没有保存在slab中的slab描述符。还有13个cache,大小从2^5-----2^17字节,分别由cache_sizes[]中的13个元素指向。专用cache则是应具体应用要求而创建的,在系统初始化时就是要把通用cache以及一部分专用cache构建起来。每个新创建的cache的描述符都会被插入到通用cache cache_cache中。需要注意的是,一旦cache被创建后就不能被删除。


    2、怎样在内核中获得拦截文件的全路径

    我在内核中对open系统调用进行拦截,拦截后得到的文件路径,当别人使用相对路径时为相对路径,只有别人在调用open时使用了全路径我才能在内核中拦截到打开文件的绝对路径。不知当别人用相对路径打开文件时,怎样才能在内核中得到所打开文件的绝对路径?

    既然是相对路径,自然是对当前路径而言,当前进程的task_struct中有两个变量fs,files含有当前打开文件信息,具体内容看看两个数据结构吧。


    3、LKM编写初级问题

    我现在在学内核模榈谋嘈?但是连一个最简单的HELLO WORLD都通不过:
    我是REDHAT7.0内核是2.2.16.
    我的程序如下
    #include
    #include
    #if CONFIG_MODVERSIONS==1
    #define MODVERSIONS
    #include
    #endif
    int init_module()
    {
    printk("hello,world
    ");
    return 0;
    }
    void cleanup_module()
    {
    printk("short is the life of a kernel module
    ");
    }
    Makefile为
    CC=gcc
    MODCFLAGS := -Wall -DMODULE -D__KERNEL__ -DLINUX

    hello.o: hello.c /usr/include/linux/version.h
    $(CC) $(MODCFLAGS) -c hello.c
    然后编译提示头文件有错
    我发现我的modversions.h为以下内容
    #error Modules should never use kernel-headers system headers,
    #error but headers from an appropriate kernel-source

    我用源码src中的modversions.h代替,然后又把源码中的models目录拷贝过来结果虽然编译通过,但是一运行就提示
    hello.o:kernel -module version mismatch
    hello.o was compiled for kernel version 2.4.0-0.26
    while this kernel is version 2.2.16-22
    望高手指点,不要跟我说升级内核,因为我要做的东西必须要在2.2.16下运行
    如果我只是包含#include
    #include
    两个头文件,然后用gcc -c -O3 hello.c编译又提示什么版本号出错

    !!I KNOW WHY!!
    Hmmm...
    You are programming in kernel and its version is 2.2.16,
    so you should do following: (I HAVE JUST SAID IT :< )

    cd /usr/include
    mv linux linux.bak
    mv asm asm.bak
    ln -s /usr/src/linux/include/linux linux
    ln -s /usr/src/linux/include/asm asm

    Then Try...
    Good Luck!

    这样行不行? 只包喊两个头文件,遍译时加上 -I/usr/include/linux/version.h

    我把源代码中includ拷入includ中就可以了!

    其实原因很简单
    redhat在发布软件时搞错啦,
    指的是2.2.16
    版本

    所以,你可疑
    如下操作
    cd /usr/include
    rm -rf linux asm
    cp -a /usr/src/linux/include/linux .
    cp -a /usr/src/linux/include/asm .

    主要目的就是替换掉kernel.headers包


    4、insmod可卸载内核问题

    我找到了一个包过滤防火墙源程序,编译通过,但insmod 时出错。报错说 unresolved symbol htons 但如果不用这个(htons)函数,我就不能把主机字节排序换成网络字节排序。我看ip_fw.c也用到了 ntohs 这个函数,为什么他能用我不能用?另外 mm_segment_t 是什么东西? get_fs() 、 set_fs()呢?这是一位高手交给我的解决之道,但可能我用的不对,依然出错。

    模块编程属于内核编程,必须使用内核向外公开的函数(内核函数),htons时属于用户级,所以insmod时在内核公开符号表(用ksyms看)找不到,内核如何分别进程此时在内核级或用户级呢,主要时通过进程的task_struct中addr_limit,get_fs和set_fs,实际就是对她的操作.
    使用:
    mem_segment_t old_fs;
    old_fs=get_fs();//保存
    。。。。。。。。
    set_fs(get_ds());
    。。。。。。。
    set_fs(old_fs)恢复
    我本来又一篇介绍这方面的文章,暂时找不到,等发现在帖出来,到时你可以参考一下。
    建议:你可以追踪htons源码,寻找其中被内核开放的函数,直接使用,这是一种内核编程的方法。

    您老人家似乎是在用gcc编译的时候未加 -O3选项,加上以后再试试。

    我按照大侠指点的作了一下。
    我把mem_segment_t old_fs
    old_fs=get_fs()
    set_fs(get_fs())放在函数开始
    set_fs(old_fs)放在函数最后。
    还是有错。
    是不是 mm_segment_t ?
    改正后
    gcc -Wall -02 -c myfirewall.c
    时出错说
    warning:implicit declaration of function get _fs
    imcompatale types in assignment
    warning:implicit declaration of function get _fs
    我查了一下 htons 他用 __bswap16()
    但是这个函数好像也是在应用级运行。 我查不到__bswap16的源代码。


    5、关于bootsect.S的一个问题

    本人在研究linux的启动代码时发现一个问题,百思不得其解,希望那位高人指点一下:
    作为bootloader, bootsect.S被读进绝对地址:0x7c00后,立即进行自我搬迁,挪到0x90000处。我认为这次的搬迁是没有意义的,因为在bootsect.S执行过程中根本不会对0x7c00以及附近的内存区进行写操作,虽然在setup.S中有可能对内核进行重定位,将内核搬到0x1000处,但那时bootsect.S已经没有存在意义了,因为它已经把setup.S以及内核读进内存了,其任务也就完成了。所以将其覆盖也无所谓。因此bootsect.S的自我搬迁就显得毫无意义了。
    我怀疑这可能是为了遵守某种协议或约定所致的,但又找不到相关的材料,那位高手对这方面有研究的话,能否指点一下?

    你讲得对,不搬迁也是可以的。我以前改过一回,也能用。不过bootsect.S是小问题,只是在你使用软盘时才用这段代码,硬盘上的lilo是不会理会它的。也就是说,硬盘lilo时,直接跳过bootsect.S的所有代码进入setup.S。

    仅供参考:如果你仅有一个linux系统,正如你所说得,但当你有多个系统时,如果你选择得启动系统不是linux,比如dos,在bootsect完成工作前要将dos引导扇区读入0x07c00,做完这一步,控制权要交还给bootsect,至于为什么要是0x07c00则是pc得向后兼容的要求。



    发布人:daming_z 来自:linuxaid