第17章 设备与模块

一、设备类型

 除了以上3种典型的设备之外,其实Linux中还有一些其他的设备类型,其中见的较多的应该算是"伪设备"。所谓"伪设备",其实就是一些虚拟的设备,仅提供访问内核功能而已,没有物理设备与之关联。典型的"伪设备"就是 /dev/random(内核随机数发生器), /dev/null(空设备), /dev/zero(零设备), /dev/full(满设备)

二、内核模块

 Linux内核是模块化组成的,内核中的模块可以按需加载,从而保证内核启动时不用加载所有的模块,即减少了内核的大小,也提高了效率。通过编写内核模块来给内核增加功能或者接口是个很好的方式,既不用重新编译内核,也方便调试和删除。

 内核模块可以带参数也可以不带参数,不带参数的内核模块比较简单。带参数的内核模块:内核中已经提供了简单的框架来给我们声明参数。

 1.module_param(name, type, perm) : 定义一个模块参数

 参数 name :: 既是用户可见的参数名,也是模块中存放模块参数的变量名

 参数 type :: 参数的类型(byte, short, int, uint, long, ulong, charp, bool...) byte型存放在char变量中,bool型存放在int变量中

 参数 perm :: 指定模块在 sysfs 文件系统中对应的文件权限(关于 sysfs 的内容后面介绍)

static int stu_id = 0;  // 默认id
module_param(stu_id, int, 0644);

 2.module_ param_ named(name, variable, type, perm) : 定义一个模块参数,并且参数对内对外的名称不一样

  参数 name :: 用户可见的参数名

 参数 variable :: 模块中存放模块参数的变量名

 参数 type和perm :: 同 module_param 中的 type 和 perm

static char* stu_name_in = "default name"; // 默认名字
module_param_named(stu_name_out, stu_name_in ,charp, 0644);
/* stu_name_out 是对用户开放的名称
*stu_name_in 是内核模块内部使用的名称
*/

 3. module_ param_ string(name, string, len, perm) : 拷贝字符串到指定的字符数组

 参数 name :: 用户可见的参数名

 参数 string :: 模块中存放模块参数的变量名

 参数 len :: string 参数的缓冲区长度

 参数 perm :: 同 module_param 中的 perm

static char str_in[BUF_LEN];
module_param_string(str_out, str_in, BUF_LEN, 0);
/* perm=0 表示完全禁止 sysfs 项 */

 4.module_ param_ array(name, type, nump, perm) : 定义数组类型的模块参数

 参数 name :: 同 module_param 中的 name

 参数 type :: 同 module_param 中的 type

 参数 nump :: 整型指针,存放数组的长度

 参数 perm :: 同 module_param 中的 perm

#define MAX_ARR_LEN 5
static int arr_len;
static int arr_in[MAX_ARR_LEN];
module_param_array(arr_in, int, &arr_len, 0644);

  5.module_ param_ array_named(name, array, type, nump, perm) : 定义数组类型的模块参数,并且数组参数对内对外的名称不一样

 参数 name :: 数组参数对外的名称

 参数 array :: 数组参数对内的名称

 参数 type,nump,perm :: 同 module_ param_ array 中的 type,nump,perm

 #define MAX_ARR_LEN 5
static int arr_len;
static int arr_in[MAX_ARR_LEN];
module_param_array_named(arr_out, arr_in, int, &arr_len, 0644);

 6.参数描述宏

 可以通过 MODULE_ PARM_ DESC() 来给内核模块的参数添加一些描述信息。这些描述信息在编译完内核模块后,可以通过modinfo命令查看。

static int stu_id = 0;  // 默认id
module_param(stu_id, int, 0644);
MODULE_PARM_DESC(stu_id, "学生ID,默认为 0"); // 这句就是描述内核模块参数 stu_id 的语句

<font color==blue size=4>内核模块相关操作:

 1.模块安装

make modules_install  <-- 把随内核编译出来的模块安装到合适的目录中( /lib/modules/version/kernel )

 2. 模块依赖性

 linux中自动生产模块依赖性的命令:

depmod <-- 产生内核依赖关系信息
depmod -A <-- 只为新模块生成依赖信息(速度更快)

 3. 模块的载入

 内核模块实验时已经用过:

insmod module.ko

<-- 推荐使用以下的命令, 自动加载依赖的模块
modprobe module [module parameters]

 4. 模块的卸载

 内核模块实验时已经用过:

rmmod module.ko

<-- 推荐使用以下的命令, 自动卸载依赖的模块
modprobe -r module

 5. 模块导出符号表

 内核模块被载入后,就动态的加载到内核中,为了能让其他内核模块使用其功能,需要将其中函数导出。内核模块中导出函数的方法:

EXPORT_SYMBOL(函数名)       <-- 接在要导出的函数后面即可
EXPORT_SYMBOL_GPL(函数名) <-- 和EXPORT_SYMBOL一样,区别在于只对标记为GPL协议的模块可见

内核对象:

 2.6内核中增加了一个引人注目的新特性--统一设备模型(device model)。

 统一设备模型的最初动机是为了实现智能的电源管理,linux 内核为了实现智能电源管理,需要建立表示系统中所有设备拓扑关系的树结构,这样在关闭电源时,可以从树的节点开始关闭。实现了统一设备模型之后,还给内核带来了如下的好处:

1.代码重复最小化(统一处理的东西多了)

2. 可以列举系统中所有设备,观察它们的状态,并查看它们连接的总线

3. 可以将系统中的全部设备以树的形式完整,有效的展示出来--包括所有总线和内部连接

4. 可以将设备和其对应的驱动联系起来,反之亦然

5. 可以将设备按照类型加以归类,无需理解物理设备的拓扑结构

6. 可以沿设备树的叶子向其根的反向依次遍历,以保证能以正确的顺序关闭设备电源

第19章 可移植性

 linux内核的移植性非常好, 目前的内核也支持非常多的体系结构(有20多个).但是刚开始时, linux也只支持 intel i386 架构, 从 v1.2版开始支持 Digital Alpha, Intel x86, MIPS和SPARC(虽然支持的还不是很完善).从 v2.0版本开始加入了对 Motorala 68K和PowerPC的官方支持, v2.2版本开始新增了 ARMS, IBM S390和UltraSPARC的支持.v2.4版本支持的体系结构数达到了15个, v2.6版本支持的体系结构数目提高到了21个.考虑到内核支持如此之多的架构, 在内核开发的时候就需要考虑编码的可移植性。

 数据对齐也是增强可移植性的一个重要方面(有的体系结构对数据对齐要求非常严格, 载入未对齐的数据可导致性能下降, 甚至错误)。数据对齐的意思就是: 数据的内存地址可以被 4 整除。

 对于结构体, 保证结构体中每个元素能够正确对齐即可。如果结构体中的元素没有对齐, 编译器会自动填充结构体, 保证它是对齐的. 比如下面的代码, 预计应该输出12, 实际却输出了24。

#include <stdio.h>
struct animal_struct
{
char dog; /* 1个字节 */
unsigned long cat; /* 8个字节 */
unsigned short pig; /* 2个字节 */
char fox; /* 1个字节 */
};
int main(int argc, char *argv[])
{
/* 在我的64bit 系统中是按8位对齐, 下面的代码输出 24 */
printf ("sizeof(animal_struct)=%d\n", sizeof(struct animal_struct));
return 0;
}

 结构体应该被填充成如下形式:

   struct animal_struct
{
char dog; /* 1个字节 */
/* 此处填充了7个字节 */
unsigned long cat; /* 8个字节 */
unsigned short pig; /* 2个字节 */
char fox; /* 1个字节 */
/* 此处填充了5个字节 */
};

 通过调整结构体中元素顺序, 可以减少填充的字节数, 比如上述结构体如果定义成如下顺序:

struct animal_struct
{
unsigned long cat; /* 8个字节 */
unsigned short pig; /* 2个字节 */
char dog; /* 1个字节 */
char fox; /* 1个字节 */
/* 此处填充了4个字节 */
};

注意: 虽然调整结构体中元素的顺序可以减少填充的字节, 从而降低内存的消耗.但是对于内核中已有的那些结构, 千万不能随便调整其元素顺序, 因为内核中很多现存的方法都是通过元素在结构体中位置偏移来获取元素的.

第20章 补丁,开发和社区

1. 加入社区

 如果想为linux贡献代码, 那么加入linux社区是必须的, 加入了社区, 不仅可以及时内核的最新消息, 而且可以及时和社区内有经验的内核开发者交流经验.同时也是提交代码和讨论代码的地方, 了解社区的规则, 融入社区环境之中, 才能更好的学习内核, 体会内核开发的乐趣和成就感.内核社区说白了就是内核邮件列表(LKML linux kernel mail list)

 订阅邮件列表的网址:http://vger.kernel.org/vger-lists.html 这里面有linux相关的各种邮件列表

 关于内核的邮件列表是: http://vger.kernel.org/vger-lists.html#linux-kernel

2. 编码风格

 社区给我们提供了学习和贡献内核的地方, 但是为了避免不必要的麻烦(被别人指责或者无人理睬), 首先得好好了解一些内核代码的编码风格.linux的编码风格都记录在 Documentation/CodingStyle 内核开发前要好好研读以下, 之后有时间我会整理到博客中.

3. 提交补丁

 准备工作都完成之后, 就可以开始内核开发之旅了 :)只要坚持不断的学习和尝试, 总有一天会为了内核贡献自己的代码, 这时候, 就需要了解如何提交代码, 也就是内核补丁.如果是发现了BUG或者有改善, 可以将BUG的描述或者改善代码发送给对应的维护者.(内核各个子系统的维护者信息在内核代码根目录下的 MAINTAINERS 文件中)生成BUG或者改善代码的补丁有2种方法:

(1)、用diff命令创建补丁

生成patch
diff -urN linux-old/ linux-new/ > my-patch # 比对整个内核代码文件夹
OR
diff -u linux-old/some/file linux-new/some/file > my-patch # 比对某个文件

 应用patch, 应用了patch之后, linux-old 和 linux-new 中的代码就一样了

cd linux-old
patch -p1 < ../my-patch # 这个命令是进入linux内核代码根目录内执行的

 PS. 还有个很有用的工具 diffstat

diffstat -p1 my-patch  # 列出补丁所引起的变更的统计(加入或移去的代码行)

(2)、用git命令创建补丁

 提交修改的或新增的代码

git commit -a   # 提交所有修改的代码
OR
git commit linux-src/some/file.c # 提交某个修改的代码
OR
git add linux-src/some/new-file.c # 把新增的文件加入版本库
git commit -a # 提交新增的文件 # 生成patch
git format-patch -N # N 是正整数, 这条命令生成最后N次提交产生的补丁
OR
git format-patch -1 # 最后1次提交产生的补丁

2017-2018-1 20179215《Linux内核原理与分析》第十周作业的更多相关文章

  1. 2017-2018-1 20179215《Linux内核原理与分析》第二周作业

    20179215<Linux内核原理与分析>第二周作业 这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型.X86汇编指令包括几种内存地址的寻址方式和push.pop.c ...

  2. 20169212《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...

  3. 20169210《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 本周作业分为两部分:第一部分为观看学习视频并完成实验楼实验一:第二部分为看<Linux内核设计与实现>1.2.18章并安装配置内核. 第 ...

  4. 2018-2019-1 20189221 《Linux内核原理与分析》第九周作业

    2018-2019-1 20189221 <Linux内核原理与分析>第九周作业 实验八 理理解进程调度时机跟踪分析进程调度与进程切换的过程 进程调度 进度调度时机: 1.中断处理过程(包 ...

  5. 2019-2020-1 20199329《Linux内核原理与分析》第九周作业

    <Linux内核原理与分析>第九周作业 一.本周内容概述: 阐释linux操作系统的整体构架 理解linux系统的一般执行过程和进程调度的时机 理解linux系统的中断和进程上下文切换 二 ...

  6. 2019-2020-1 20199329《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 一.上周问题总结: 未能及时整理笔记 Linux还需要多用 markdown格式不熟练 发布博客时间超过规定期限 二.本周学习内容: <庖丁解 ...

  7. 2019-2020-1 20209313《Linux内核原理与分析》第二周作业

    2019-2020-1 20209313<Linux内核原理与分析>第二周作业 零.总结 阐明自己对"计算机是如何工作的"理解. 一.myod 步骤 复习c文件处理内容 ...

  8. 2018-2019-1 20189221《Linux内核原理与分析》第一周作业

    Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...

  9. 《Linux内核原理与分析》第一周作业 20189210

    实验一 Linux系统简介 这一节主要学习了Linux的历史,Linux有关的重要人物以及学习Linux的方法,Linux和Windows的区别.其中学到了LInux中的应用程序大都为开源自由的软件, ...

  10. 2018-2019-1 20189221《Linux内核原理与分析》第二周作业

    读书报告 <庖丁解牛Linux内核分析> 第 1 章 计算工作原理 1.1 存储程序计算机工作模型 1.2 x86-32汇编基础 1.3汇编一个简单的C语言程序并分析其汇编指令执行过程 因 ...

随机推荐

  1. [JavaScript]常用的页面倒计时

    倒计时是web开发中比较常用的,以下列出常用的几个倒计时方法,仅供参考: 一 :页面倒计时 原理一般都是通过 setTimeout 或 setInterval 函数实现,下面是一个最简单的倒计时 &l ...

  2. 算法寒假实习面试经过之 十一贝(offer) 联想研究院(电话一面 被拒)

    联想研究院 1面 自我介绍 聊比赛,讲了讲jdd的. 感觉都快要背过了... 之前重复的问题就不说了,说一下印象比较深的 adaboost 与gbdt的区别 随机森林,如果有t个特征,n个树,每个树深 ...

  3. 对”唯一键可以包含NULL值,并且每个NULL值都是唯一的(即NULL!=NULL)“理解

    因为最近在写一篇关于字符串模糊检索的论文,开始比较细致的研究数据库(MySQL)中的index问题,变到图书馆借了本<Effective MySQL之SQL语句最优化>(Ronald Br ...

  4. springboot-controller的使用

    获取url中的数据: @RestController public class HelloController { @RequestMapping(value="/say/{id}" ...

  5. python中编写无参数decorator

    Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数. 使用 decorator 用Python提供的 @ 语法,这样可以避免手动编写 f = de ...

  6. Docker 数据管理-bind mount

    Use bind mounts Bind mounts have been around since the early days of Docker. Bind mounts have limite ...

  7. Gitblit搭建及Git协作开发流程

    1. 概述 目前主流的是git作为自己代码管理,但是采用github需要付费才能够使用,如果不付费,代码需要公开.创业团队及小型开发团队都有必要搭建自己的代码服务器,自己摸索需要一定的时间,会赶不及项 ...

  8. poj 3126 Bfs

    Prime Path Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14539   Accepted: 8196 Descr ...

  9. python练习_sed替换

    python练习_sed替换 需求: 做一个sed替换小程序,实现在windows下可以与实现linux中sed替换的功能 支持正则(re模块) 以下代码实现的功能与思路: 功能: (1)支持文件内容 ...

  10. 解决Pycharm中matplotlib画图出错问题(AttributeError: module 'matplotlib' has no attribute 'verbose')

    最近在Linux中使用pycharm过程中使用matplotlib无法画图,总是提示错误 /usr/bin/python3. /home/leo/PycharmProjects/untitled1/E ...