当前位置:Linux教程 - Linux - 在Linux可加载内核模块中探秘(6)

在Linux可加载内核模块中探秘(6)



         第一部分:基础知识
    第六章:内核守护进程
    作者:CoolBoy
    今天我们将结束关于LKM基础知识部分的讲解,首先讲讲内核守护进程。

      内核守护进程的运行文件是(/sbin/kerneld),从文件的名字就可以猜到,这个进程会一直运行在用户空间,等待着其他动作的发生。当然,有些同学的机器上是没有运行这个进程的,这样就必须在build内核的时候,激活Kerneld选项。

      Kerneld的工作原理是这样的:如果内核需要去访问某个设备,而恰好此时这个设备又是不可用的,那么它是不是要产生一个访问错误呢?答案是NO!这时它一定会去找Kerneld帮忙,如果Kerneld有能力提供那个设备的访问接口,那么它就会加载相应的LKM程序(一般作为设备驱动程序),然后内核就可以访问到这个设备了。大家看到,内核守护进程实际上就是为内核提供服务的常驻程序,它能在需要(或者不需要)的时候,加载(或者是卸载)相应的LKM程序,但大家还应该了解的是,上述过程是同时发生于用户空间和内核空间的。

      Kerneld存在于用户空间,如果在内核空间运行着的内核需要kerneld提供一个新的模块程序给它,它就会给Kernel发送一个字符串,字符串里存放了需要加载何种模块程序的信息。当然,内核程序也许并不知道某个具体的模块程序(*.OBJ)是什么名字,那么它就会发出一个通用的字符串(例如eth0表示网卡0),这时Kerneld就会去查找/etc/modules.conf列表,从中得到设备的对应的LKM程序名。如下面这行,意思是eth0对应DEC的TULIP驱动程序:

      # /etc/modules.conf
      alias eth0 tulip

      Kerneld从内核得到字符串并找到对应的LKM程序的过程,是在用户空间中完成的。而在内核空间完成的动作,需要调用到四个内核函数。这几个函数其实都调用了系统调用kerneld_send(关于kerneld_send怎样被调用,参见linux/kerneld.h),如下列出了这四个函数:

    int request_module (const char *name); 告诉kerneld核心所需要的模块名字(或者别名)

    int release_module (const char* name, int waitflag); 卸载一个模块

    int delayed_release_module (const char *name); 延迟卸载

    int cancel_release_module (const char *name); 取消对delayed_release_module的调用

    (注:核心2.2.x使用另外的一种请求加载新模块的机制)

      好了,这下我们可以来创建一个我们自己的设备驱动程序了。我们创建的这个程序很简单,它几乎不做什么事情,只是作为一个演示,但如果你有兴趣加些代码,就可以监视TTY(终端)的动作了。下面就是这个程序的代码:

    #define MODULE
    #define __KERNEL__

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    /*这里什么都没做,只是演示一下*/
    static int driver_open(struct inode *i, struct file *f)
     {
      printk(\"<1>Open Function\\n\");
      return 0;
     }

    /*把将要运用于我们的LKM中的各个函数注册*/
    static struct file_operations fops = {
    NULL,  /*lseek*/
    NULL,  /*read*/
    NULL,  /*write*/
    NULL,  /*readdir*/
    NULL,  /*select*/
    NULL,  /*ioctl*/
    NULL,  /*mmap*/
    driver_open,  /*open*/
    NULL,  /*release*/
    NULL  /*fsync...*/
    };

    int init_module(void)
     {
      /*register driver*/
      if(register_chrdev(40, \"driver\", &fops)) return -EIO;
      return 0;
     }

    void cleanup_module(void)
     {
      /*unregister*/
      unregister_chrdev(40, \"driver\");
     }

      其中最最最重要的函数是register_chrdev(...),它将我们的驱动程序注册为主注册号40,如果你访问此驱动,按下面的方法做:

    # mknode /dev/driver c 40 0
    # insmod driver.o

      然后就可以访问此驱动程序了(由于版面有限,这个驱动没做任何事情)。file_operations结构 提供了我们将向系统提供的一切函数。大家可以看到这里仅实现了一个哑元函数OPEN,它只打 印一点东西。不过,很显然,利用上述方法,你可以对你的设备进行任何操作。实作一下,如果你打算记 录下一些有趣的数据(例如键盘按键记录),你可以在你的设备驱动中内建一个缓冲区,然后通过设备设 备输出缓冲区中的内容。

      今天就讲到这里了。基础部分的知识介绍完了,不知道大家有什么意见?下章我们将会作很多有趣的“整蛊程序”,欢迎来参观哦!



    发布人:Crystal 来自:Linux专区