struct blk_operations 给他初始化,和字符设备的 file_operations一样。但是,块设备一般也就实现
open,release,他和字符设备不样,用户空间不能直接调用驱动,文件系统有多种,文件系统这一层已经实现了
读写等操作。
1,注册设备号,major = register_blk(major,"name");
如果major传递的是0,那么,内核会分配一个主设备号给设备.和字符设备的注册不一样的是,
块设备的次设备号是在gendisk中给出的。
2, 给虚设备分配空间,因为这里用的是RAM来虚拟的disk,所以给他分配空间。
3,初始化设备结构体得成员,主要的几个是lock,queue,gendisk.
锁调用spin_lock_init,请求队列用 blk_init_queue(fun,&lock),在这个函数中绑定请求队列的后台fun,把锁也
传递过去,返回值是请求队列。gendisk用alloc_disk()由内核分配,不能直接定义。
设定扇区大小,调用 blk_queue_hardsect_size(queue,size),因为扇区是给请求队列知道的,所以参数中传递了队列和
大小。
初始化 gendisk,刚才只是分配了gendisk,主要的是gendisk的major,first_minor,fops,queue,private_data等成员赋值。
4,注册设备,add_disk.这一步一定要在最后做,一旦add,内核就认为设备准备好了。
请求队列处理函数:
1,检查合法性,用CURRENT宏或者elv_next_request来从队列中获得请求队列上的第一个请求,只是获得,这里并没有把他从队列
中干掉,只有当请求完成了才离开队列。用一个 request 结构体得到请求后,也就得到了从用户空间发过来的操作请求,对request
的请求合法性进行检查。
2,数据传输,memcpy(), 操作buffer,也就是对文件系统这一层的buffer读写。这是和字符设备不用样的地方,所以字符设备在跨空间读写的时候
要用copy_to_user,防止用户空间传递过来的东西不会破坏内核。
3,清除请求,end_request ,告知内核,处理完成,同时,这个函数也会使CURRENT宏或者elv_next_request指向请求队列的下一个request.
4,返回。
一般请求函数不会去做大量的工作,当收到请求后,创建一个内核线程去处理请求,也就是他只负责接收请求,唤醒线程。没有请求时让线程睡眠。