版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、如果只是为了应付考试,这个文档就太啰嗦了,不用看,不过还是可以帮助记忆,考试只会考其中加粗字体的几个函数中的一个,至于是 哪个我不能断定,因此要记的还是比较多的,要是能理解就更好了,结合课本和下面的解释应该能大体上弄明白这个虚拟块设备驱动的 实现过程, 毕竟设备驱动是内核的一部分, 光看下面的解释也是还是很头晕的, 不过坚持看下去还是有收获的, 我也差不多花了半天时间, 不过,要是打算的话就可以直接跳过了。#define MAJOR_NR 70 /我们创造的虚拟块设备的主设备号#define DEVICE_NAME “bdemo”/我们创造的虚拟块设备的名字,当设备加载成功后可用 lsmod
2、命令查看到该设备模块名 #define blkdemo_devs 2 /虚拟块设备的个数#define blkdemo_rahead 2 /读取块设备时预读的扇区个数#define blkdemo_size 4 /每个虚拟块设备的大小,单位为 KB#define blkdemo_blksize 1024 /设备每个数据块的大小,即 block ,单位为字节#define blkdemo_hardsect 512 /设备每个扇区的大小,单位为字节struct blkdemo_device / 这里定义了我们将要创造的虚拟块设备的数据结构intsize; / 用来记录真实块设备的容量,即下面 da
3、ta 指针所指向数据存储区的大小intuse_cnt; / 用来记录正在使用该块设备的程序的个数inthardsect; / 用来保存该块设备每个扇区的大小,单位为字节,即设备的使用计数u8*data; / 该指针所指向的内存区域就是该块设备真正用来存储数据的区域,在该设备还未被加载函数初始化时,该指针为 / 空,即系统还没有为该设备分配内存区域。;static int blkdemo_sizesblkdemo_devs; /用来保存我们创建的所有虚拟块设备的大小,单位为 KBstatic int blkdemo_blksizesblkdemo_devs; /用来保存我们创建的所有虚拟块设备中
4、每个数据块的大小,单位为字节 static int blkdemo_hardsectsblkdemo_devs;/用来保存我们创建的所有虚拟块设备中每个扇区的大小,单位为字节/上面的这三个数组将会在我们加载这些设备时被注册到内核的数据结构中 (即让内核中与之相关的一些指针指向它们, 让内核能够读取 我们所创建的设备的一些重要信息/对于一个新的设备,内核肯定不知道他为何物,要想让内核识别我们自己创造的设备,则必须将该设备的一些信息、使用这个设备的方 /法等告诉内核, 由于内核早已编译成型, 至于如何去告诉内核就早已模式化。 内核中有几个指针数组 (书本 page81 专门用来完成上面 的部分任务
5、:/ blk_size;/ blksize_size;/ hardsect_size;/ read_ahead;/这几个数组都为每一个主设备号留有一个位置,对于 2.4的内核,主设备号和次设备号均用 8位二进制来表示(即短整型的高八位和 /低八位 ,因此这几个数组都包含有 256个元素,每个元素都是与主设备号对应的一个指针,如果主设备号所对应的设备不存在,则该 /指针置为空 (NULL,其实其中很多指针都为空,因为一般电脑上都没有那么多不同类型的块设备,当然,对于我们所创造的这个块设 /备而言,它与系统中所存在的其他块设备的类型都不同,要为其确定一个主设备号,这个没什么硬性的规定,只要找一个没
6、被使用的主 /设备号就可以了,这个程序中使用的是 70(前面的 MOJOR_NR宏 。上面我们定义了保存有虚拟块设备信息的数组,现在只要将他们的 /首地址赋给这几个数组中下标 70(主设备号所对应的指针元素即可。这一过程是在后面的加载函数中完成的。static int blksize = blkdemo_blksize;struct blkdemo_device blkdemo_devblkdemo_devs;/这里才真正创建了我们虚拟块设备对应的结构体变量 (一个全局数组 , /每个元素为对应一个虚拟块设备虚拟块设备的打开函数 (open(:int blkdemo_open(struct i
7、node *inode, strcut file *filp /设备文件对应的节点 (inode结构中包含有对应的设备号intnum;num = DEVICE_NR(inode->i_rdev;/用 DEVICE_NR宏可求出该节点所对应设备的次设备号,所以 num 即为次设备号 if (!blkdemo_devnum.use_cnt /如果该设备的使用计数为 0,则说该设备没有被任何程序使用,当虚拟块设备没有被 /任何程序使用时,内核先前为该设备所分配的存储区很可能已经被释放掉了,甚至对于可移动设备而言,有可能该设备都被拔掉了(当 /然,我们的虚拟块设备是不可能的 ,因此,在打开该设备
8、时要进行严格的检查,不然会导致设备打开出错而造成系统崩溃。check_disk_change(inode->i_rdev;/首先检查该块设备是否发生了变化,比如已经被移除了(该设备不可能,所以 /此处没有用 if 来判断,只是形式的调用了一下该函数。if(!blkdemo_devnum.data/然后判断该设备的数据存储区域是否已经被释放掉了returnENOMEM;/如果是,则返回,告知系统该设备无法打开, -ENOMEM 是一个内核中定义的宏,它代表的意思是 /“ error,no memory” 。/如果上述情况均未发生,一切正常,则打开设备,对于这个虚拟的块设备,其实没有什么好打
9、开的,不过还是意思一下:blkdemo_devnum.use_cnt+;/将设备的使用计数加 1,表示又多了个程序使用该设备。MOD_INC_USE_COUNT;/并且将内核所管理的模块使用计数也加 1, 好让内核也知道多了一个程序使用该虚拟设备模块。 模块使 /用计数是内核管理模块时要用的,只有当一个设备的模块使用计数为 0时才能卸载该模块,这个值也可以通过 lsmod 命令查看到 return(0;/返回 0,表示设备已成功打开虚拟块设备的释放函数 (release(:int blkdemo_release(struct inode *inode, struct file *filp/释放
10、并不代表将此设备从内核中移除了,他是对调用它的程序而言的,只表示这个程序不再使用该设备了intnum;num = DEVICE_NR(inode->i_rdev;/求出设备的次设备号blkdemo_devnum.use_cnt-;/既然使用该设备的程序少了一个,则应该将该设备的使用计数减 1MOD_DEC_USE_COUNT;/ 并且将内核所管理的模块使用计数也减 1return(0;/返回 0,表示设备释放成功虚拟块设备的请求函数 (request(:void blkdemo_request(request_queue_t *q /块设备和字符设备在数据的读写是有区别的。对于块设备,程
11、序对数据读写的请求一般不会立即得到回应,程序首先要提出对数据 /的请求,此时内核会动态的分配一个 request 结构(page74,图 7-1中有 request 结构的抽象描述 ,并将请求的详细信息记录到 /这个 request 结构中,然后将这个结构按照某些规则插入到该设备的请求队列中,当系统处于较为合适的状态时,内核就会对队列上 /的所有请求进行集中处理。 采用这些繁琐的方法都由真实块设备的物理特性决定的,因为大部分块设备都和硬盘类似, 读取数据时要进 /行寻道等一些复杂的命令操作, 而这是一个相当耗时的过程, 如果每当有程序请求数据时内核就立即去操作磁盘, 那么系统大部分宝贵 /的时
12、间都被消耗在了等待磁盘响应上了, 因此内核中构建了一套专门操作块设备的方法, 来对请求的数据进行集中处理, 以提高磁盘的 /吞吐量和系统的整体性能, request(函数的任务就是按顺序处理这条请求队列,直到队尾, /除非出现意外错误而返回。struct request *req;int res = 1; /用来记录对当前请求的处理是否成功,成功则置 1,失败则清 0,供后面的 end_request(函数使用。intnum;intsize;u8*ptr;while (1 INIT_REQUEST;/测试当前的请求是否有效req=CURRENT; /CURRENT指针由内核中的 end_req
13、uest(函数管理,它指向请求队列中当前要处理的 request 结构。 num=DEVICE_NR(req->rq_dev;/获取所请求的设备的次设备号ptr = blkdemo_devnum.data + req->sector * blkdemo_devnum.hardsect;/ 设备数据存储区的首地址 + 请求的首个扇区 * 该设备每个扇区的字节大小,最后, ptr 指向所要请求的数据 size = req->current_nr_sectors * blkdemo_devnum.hardsect;/ 当前请求的扇区总数 * 该设备每个扇区的字节大小,因此 size
14、 为当前请求所请求的总字节数if (ptr + size > blkdemo_devnum.data + blkdemo_devnum.size /判断所请求数据的地址是否超出 /了该设备的数据存储区的范围。超出范围后会导致内存溢出,造成系统崩溃,决不能容忍。printk(KERN_WARNNING “blkdemo: request past end of devicen”; /向控制台或日志打印出警告信息 res=0;/请求失败, res 置 0/如果正常则下面打印出当前请求的详细信息(仅调试时使用,可以不写printk(“<1> request %p: cmd %i s
15、ec %li (nr.%lin”, req,/<1>和 KERN_ALERT是等价的,这是内核中定 req->cmd, req->sector, req->current_nr_sectors;/义的 8种日志级别宏之一(page43switch(cmd /判断当前请求要对所请求的数据做何种操作caseREAD:/如果是读,则,memcpy(req->buffer,ptr,size; /把从 ptr 开始的 size 字节复制到发出该请求的程序所提供的缓冲区中去 res=1; /完成了请求, res 置 1break;caseWRITE:/如果是写,则,me
16、mcpy(ptr,req->buffer,size; /把发出该请求的程序的缓冲区中的数据复制到该设备中 ptr 所指向的内存区 res=1;/完成了请求, res 置 1break;default: /未知请求res=0; /无法完成, res 置 0end_request(res;/根据请求是否成功来调整 CURRENT 指针变量的值,为处理请求队列中的下一个请求作准备struct block_device_operations blkdemo_bdops = /初始化虚拟块设备操作函数接口open: blkdemo_open,release: blkdemo_release,;虚拟
17、块设备的加载函数:static int _init blkdemo_init(void/_init为加载函数标志,用此标志修饰的函数只能在模块被插入内核由内核调用 inti;intret;ret = devfs_register_blkdev(MAJOR_NR, DEVICE_NAME, &blkdemo_bdops;/注册块设备,该函数成功时返回主设 /备号,失败时返回负值,当参数中主设备号 MAJOR_NR为 0时,自动为设备分配主设备号,非 0时使用 MAJOR_NR指定的主设备号 if (ret < 0 /如果返回值小于 0,说明设备注册失败printk(KERN_WAR
18、NNING “devfs_register_blkdev( failedn”; /打印出警告信息return(ret;/返回错误代号if (MAJOR_NR = 0/如果 MAJOR_NR为 0,则blkdemo_major=ret;/使用系统自动分配的主设备号else/否则blkdemo_major=MAJOR_NR;/直接使用我们指定的主设备号blk_init_queue(BLK_DEFAULT_QUEUE(blkdemo_major,blkdemo_request;/内核为每个主设备号都保留了一个请求 /队列, 也是通过一个数组实现的, BLK_DEFAULT_QUEUE能返回该默认的请
19、求队列, blk_init_queue(函数通过创建一个请求队列 /头将该队列和处理该请求队列的 request(关联起来/ 下面的就开始将我们所创造的虚拟块设备的信息告诉系统:read_aheadblkdemo_major = blkdemo_rahead; /告诉系统该类型块设备的预读扇区数for (i = 0; i < blkdemo_devs; i+blkdemo_sizesi=blkdemo_size;/确定每个块设备的大小,以 KB 为单位blk_sizeblkdemo_major = blkdemo_sizes;/告诉系统保存有这些块设备的大小的数组的内存首地址for (i
20、 = 0; i < blkdemo_devs; i+blkdemo_blksizesi=blkdemo_blksize;/确定每个块设备的每个数据块的大小,以字节为单位blksize_sizeblkdemo_major = blkdemo_blksizes;/告诉系统保存有这些块设备的每个数据块大小的数组的首地址 for (i = 0; i < blkdemo_devs; i+blkdemo_hardsectsi=blkdemo_hardsect;/确定每个块设备的每个扇区的大小,以字节为单位hardsect_sizeblkdemo_major = blkdemo_hardsect
21、s;/告诉系统保存有这些块设备的每个扇区大小的数组的首地址for (i = 0; i < blkdemo_devs; i+register_disk(NULL, MKDEV(blkdemo_major, i, 1, &blkdemo_bdops,/注册每个块设备分区。由于我们的虚 blkdemo_size<<1; /拟块设备没有实行分区,相当于只有一个分区,也就没用到 gendisk 分区结构, /因此第一个参数为 NULL ,表示不做任何分区操作。 MKDEV(宏能够将主设备号和次设备号组合成一个完整的设备号,最后一个参数要 /将 blkdemo_size左移 1位
22、是因为 blkdemo_size的单位为 KB ,而 register_disk要求的单位是扇区,该块设备的一个扇区为 /512字节,所以要将 blkdemo_size乘以 2才是扇区数,即左移两位。for (i = 0; i < blkdemo_devs; i+ /初始化前面所创建的虚拟块设备的结构体变量blkdemo_devi.size = 1024 * blkdemo_size;/确定该块设备的大小,单位为字节blkdemo_devi.hardsect=blkdemo_hardsectsi;/确定该块设备每个扇区的字节数,/ 由于 blkdemo_hardsects数组保存的也是这个值,并且已经在前面初始化,因此可直接赋给该结构中的 hardsectblkdemo_devi.data = kmalloc(blkdemo_size * blkdemo_blksize * sizeof(char, GFP_KERNEL; / 根据上面的大小为该虚拟设备分配数据存储区,上面 kmalloc(函数参数中的“ *”号都是乘号,不是指针。 GFP_KERNEL是内核分 /配内存页的一种方式,以这种方式分配内存时成功的几率最大,但也可能失败,失败时返回
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 南京工业大学浦江学院《图形与标志设计》2021-2022学年第一学期期末试卷
- 非特异性免疫说课稿
- 深圳市万豪御景苑施工组织设计
- 南京工业大学浦江学院《企业家精神》2022-2023学年第一学期期末试卷
- 【初中化学】化学反应的定量关系单元综合题-2024-2025学年九年级化学人教版上册
- 南京工业大学浦江学院《公益组织内部治理和战略管理》2022-2023学年第一学期期末试卷
- 精神科责任自负协议书(2篇)
- 南京工业大学《有机波谱分析》2022-2023学年第一学期期末试卷
- 南京工业大学《无机非金属材料工学》2021-2022学年第一学期期末试卷
- 教育4-5岁幼儿尊重并接纳不同群体的实施方案
- (外研版3起)英语四年级上册单词字帖书写练习(手写体)高清打印版
- 《泡沫灭火系统》课件
- 小学教学质量提升关键培养学生良好的学习习惯
- 古代辞章领略古代辞章的风华与韵味
- 开放性指骨骨折的护理查房课件
- Part3-4 Unit5 Ancient Civilization教案-【中职专用】高一英语精研课堂(高教版2021·基础模块2)
- 2023年山东济南市文化和旅游局所属事业单位招聘42人笔试参考题库(共500题)答案详解版
- 开拓海外市场:2024年新年计划
- 2023-2024学年辽宁省沈阳126中八年级(上)期中数学试卷(含解析)
- 生产检验记录表
- 化工厂设计车间布置设计
评论
0/150
提交评论