第七章 块设备驱动程序_第1页
第七章 块设备驱动程序_第2页
第七章 块设备驱动程序_第3页
第七章 块设备驱动程序_第4页
第七章 块设备驱动程序_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

上章回顾 块设备驱动程序第7章预习检查本章目标掌握Linux下块设备驱动程序的设计方法本章结构块设备驱动程序block_device_operations结构体

gendisk结构体请求和请求队列Linux块设备驱动结构

块设备驱动注册与注销

块设备的打开与释放

块设备的ioctl函数

块设备的I/O请求处理

块设备与字符设备的区别属性\类别块设备字符设备访问单位/次有固定大小无固定大小随机访问(lseek)支持不支持用户直接访问不可可以驱动程序复杂相对简单块设备驱动程序的特点块设备接口相对复杂,不如字符设备明晰易用块设备驱动程序对整个系统的性能影响较大,速度和效率是设计块设备驱动程要重点考虑的问题系统中使用缓冲区与访问请求的优化管理(合并与重新排序)来提高系统性能块设备驱动的实现步骤确定主设备号和次设备号确定设备名称创建设备文件实现块设备驱动程序实现block_device_operations结构体实现request(请求)实现初始化函数,注册块设备实现销毁函数,取消块设备7.1.1block_device_operations结构体structblock_device_operations{ int(*open)(structinode*,structfile*); int(*release)(structinode*,structfile*); int(*ioctl)(structinode*,structfile*,unsigned,unsignedlong); long(*unlocked_ioctl)(structfile*,unsigned,unsignedlong); long(*compat_ioctl)(structfile*,unsigned,unsignedlong); int(*direct_access)(structblock_device*,sector_t,unsignedlong*); int(*media_changed)(structgendisk*); int(*revalidate_disk)(structgendisk*); int(*getgeo)(structblock_device*,structhd_geometry*); structmodule*owner;};7.1.1block_device_operations结构体int(*open)(structinode*,structfile*); int(*release)(structinode*,structfile*); int(*ioctl)(structinode*,structfile*,unsigned,unsignedlong);int(*media_changed)(structgendisk*);与字符设备中对应函数功能作用相同,当设备被打开或者关闭时调用它们块设备层会首先截取大量的标准请求,因此大多数块设备的ioctl函数都十分短小内核调用该函数以检查用户是否更换了驱动器内的介质表示一个独立的磁盘7.1.2gendisk结构体每一个块设备物理实体由一个gendisk结构体来表示每个gendisk可以支持若干个分区每个gendisk中包含本物理实体的全部信息及操作函数接口整个块设备的注册过程都是围绕gendisk来开展的7.1.2gendisk结构体structgendisk{ intmajor; /*majornumberofdriver*/ intfirst_minor; intminors;/*maximumnumberofminors,=1for

disksthatcan'tbepartitioned.*/ chardisk_name[32]; /*nameofmajordriver*/ structhd_struct**part; /*[indexedbyminor]*/

intpart_uevent_suppress; structblock_device_operations*fops; structrequest_queue*queue; void*private_data; sector_tcapacity;

intflags; structdevice*driverfs_dev; structkobjectkobj; structkobject*holder_dir; structkobject*slave_dir; structtimer_rand_state*random; intpolicy; atomic_tsync_io; /*RAID*/ unsignedlongstamp; intin_flight; #ifdef CONFIG_SMP structdisk_stats*dkstats; #else structdisk_statsdkstats; #endif}用于Linux的驱动模型7.1.2gendisk结构体设备号,及设备名

各种设备操作structblock_device_operations*fops; 管理设备I/O请求structrequest_queue*queue;sector_tcapacity以512字节为一个扇区时,该驱动器可包含的扇区数,驱动程序不能直接设置该成员,而要将扇区数传递给set_capacity

intmajor; /*majornumberofdriver*/ intfirst_minor; intminors;/*maximumnumberofminors,=1for *disksthatcan'tbepartitioned.*/chardisk_name[32]; /*nameofmajordriver*/7.1.2gendisk结构体分配gendisk并初始化向系统注册卸载gendisk计数操作get_diskput_diskstructgendisk*alloc_disk(intminors)voiddel_gendisk(structgendisk*disk)voidadd_disk(structgendisk*disk)7.1.3请求与请求队列request(请求)结构的主要成员

sector_tsector;unsignedlongnr_sectors;unsignedintcurrent_nr_sectors;还没有传输的第一个扇区等待传输扇区的总量当前Bio中剩余的扇区数structbio*biochar*buffer请求的bio结构链表,需要使用rq_for_each_bio访问sector_tsector;unsignedlongnr_sectors;unsignedintcurrent_nr_sectors;用来查找需要传输的缓冲区7.1.3请求与请求队列内核扇区和硬件扇区的转换内核总是认为扇区大小是512字节,而硬件扇区却不都是512字节,所以要相应的转换。调用blk_queue_hardsect_size设置硬件扇区大小将硬件扇区数转换成内核扇区数sectors=nsectors*(hardsect_size/KERNEL_SECTOR_SIZE);nsecotrs:硬件实际的扇区数;hardsect_size:硬件扇区大小;KERNEL_SECTOR_SIZE:内核扇区大小512字节;sectors:对应于内核扇区大小的扇区总数通过set_capacity()可以设置硬件存储器的实际容量set_capacity(structgendisk*gd,sector_tsectors);blk_queue_hardsect_size(request_queue_t*queue,unsignedshortmax);7.1.3请求与请求队列请求队列(request_queue)块设备的请求队列指包含块设备I/O请求的序列。创建和初始化请求队列的函数是:释放和删除请求队列返回下一个需要处理的请求指针

将请求从队列中删除request_queue_t*blk_init_queue(request_fn_proc*request,spinlock_t*lock);voidblk_cleanup_queue(request_queue_t*);structrequest*elv_next_request(request_queue_t*queue);voidblkdev_dequeue_request(structrequest*req);7.17.1.3request与bio结构体

请求队列(request_queue)将删除的请求再次加入到队列设置请求参数voidelv_requeue_request(request_queue_t*queue,structrequest*req);voidblk_queue_max_sectors(request_queue_t*queue,

unsignedshortmax);voidblk_queue_max_phys_segments(request_queue_t*queue, unsignedshortmax);voidblk_queue_max_hw_segments(request_queue_t*queue, unsignedshortmax);voidblk_queue_max_segment_size(request_queue_t*queue, unsignedintmax);voidblk_queue_hardsect_size(request_queue_t*queue, unsignedshortmax);7.2块设备驱动的注册与注销块设备驱动注册函数块设备驱动注销函数intregister_blkdev(unsignedintmajor,constchar*name); intunregister_blkdev(unsignedintmajor,constchar*name);7.2块设备驱动的注册与注销块设备驱动初始化函数主要工作分配、初始化请求队列,绑定请求队列和请求函数分配、初始化gendisk,给gendisk的major、fops、 queue等成员赋值,最后添加gendisk。注册块设备驱动。7.2块设备驱动的注册与注销staticint__initxxx_init(void){ //块设备驱动注册 if(register_blkdev(XXX_MAJOR,“xxx”)) { err=-EIO; gotoout; }

//请求队列初始化xxx_queue=blk_init_queue(xxx_request, xxx_lock); if(!xxx_queue) { gotoout_queue; } //硬件扇区尺寸设置

blk_queue_hardsect_size(xxx_queue, xxx_blocksize);

//gendisk初始化 xxx_disks->major=XXX_MAJOR; xxx_disks->first_minor=0; xxx_disks->fops=&xxx_op; xxx_disks->queue=xxx_queue; sprintf(xxx_disks->disk_name, “xxx%d”,i);

set_capacity(xxx_disks,xxx_size*2); add_disk(xxx_disks);//添加gendisk return0;out_queue:unregister_blkdev(XXX_MAJOR, “xxx”);out:put_disk(xxx_disks); blk_cleanup_queue(xxx_queue);

return–ENOMEM;}7.2块设备驱动的注册与注销

块设备驱动退出函数主要工作清除请求队列;删除gendisk和对gendisk的引用;删除对块设备的引用,注销块设备驱动;7.2块设备驱动的注册与注销staticvoid__exitxxx_exit(void)

{

if(bdev)

{

invalidate_bdev(xxx_bdev,1); blkdev_put(xxx_bdev);

}

del_gendisk(xxx_disks);//删除gendisk

put_disk(xxx_disk);

blk_cleanup_queue(xxx_queue);//清除请求队列

unregister_blkdev(XXX_MAJOR,“xxx”);

}7.3块设备的打开与释放块设备驱动的open()和release()函数并非是必须的.open()函数模板release()函数模板

staticintxxx_open(structinode*inode,structfile*filp){ structxxx_dev*dev=inode->i_bdev->bd_disk->private_data; filp->private_data=dev;//赋值file的private_data … return0;}staticintxxx_release(structinode*inode,structfile*filp){ structxxx_dev*dev=inode->i_bdev->bd_disk->private_data; … return0;}7.4块设备的ioctl函数实际上在一个现代块设备驱动程序中,许多ioctl命令根本就不用实现。或只需实现很少部分。intxxx_ioctl(structinode*inode,structfile*filp unsignedintcmd,unsignedlongarg){ longsize;

structhd_geometrygeo;

structxxx_dev*dev=filp->private_data; switch(cmd){ caseHDIO_GETGEO: size=dev->size*(hardsect_size/KERNEL_SECTOR_SIZE);

geo.cylinders=(size&~0x3f)>>6;

geo.heads=4;

geo.sectors=16;

geo.start=4;

if(copy_to_user((void__user*)arg,&geo,sizeof(geo))) return-EFAULT;

return0;

} return-ENOTTY;/*未知命令*/}即使块设备没有磁道和柱面,通常也要模拟提供这些信息,主要是为了让fdisk等工具可以在设备上工作7.5块设备的I/O请求处理块设备驱动对块设备进行读、写主要通过request来实现。

块设备驱动请求函数的原型为: voidrequest(request_queue_t*queue);块设备驱动程序处理请求的过程请求处理开始获取当前请求合法读/写请求结束否是写操作读操作读写7.5块设备的I/O请求处理 1staticvoidxxx_request(request_queue_t*q) 2{ 3 structrequest*req; 4 while((req=elv_next_request(q))!=NULL) 5 { 6 structxxx_dev*dev=req->rq_disk->private_data; 7 if(!blk_fs_request(req))//判断是否是文件系统请求? 8 { 9 printk(KERN_NOTICE“Skipnon-fsrequest\n”); 10 end_request(req,0);//通知请求处理失败 11 continue; 12 } 13 xxx_transfer(dev,req->sector,req->current_nr_sectors, 14 req->buffer,rq_data_dir(req));//处理这个请求 15 end_request(req,1);//通知成功完成这个请求 16 } 17}

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论