java打印对象内存地址 分布式事务 事务消息 分布式事务 几种解决方案 分布式事务-Seata 分布式事务-Seata 分布式事务-LCN-TCC 分布式事务-LCN 分布式事务-消息队列-定时任务-本地事件表 Zuul网关实战02 Zuul网关实战01 灰度发布落地实战2 灰度发布落地实战1 Gsnova on Heroku build Systemd Debian system initialization manage multi id_rsa ubuntu 64bits cannot run 32bits app REHL power auditing Debug Assembly for ARMv8 on QEMU ARM体系结构--寄存器 Run Debian iso on QEMU ARMv8 QEMU ARM64 guide cross compiler install buildroot install QEMU install python入门--数据结构 python入门--内置数据类型 python入门--类 异常 python入门--条件表达式 方法 python入门--数字 字符串 数组 RTC驱动分析 块设备驱动 TCP UDP socket 触摸屏驱动 USB驱动 LED按键中断 LCD 驱动 驱动信号 根文件系统 实验 内核实验 字符设备驱动程序 绪论 uboot 实验 LCD 实验 系统时钟和UART 中断控制器 Nand Flash控制器 MMU 实验 储存管理器实验 GPIO实验 点亮LED 编译加载驱动 制作烧写内核 dnw替代方法 MINI2440 TQ2440安装配套Linux 使用NFS 制作烧写跟文件系统 grub引导Windows 烧写裸版程序-linux Ubuntu 网络没有 eth0 Linux自动挂载 烧写裸板程序 电路基础 Mac词典 Vim插件 Assembly 综合研究 Assembly 指令总结 Assembly 直接定址表 Assembly 使用BIOS进行键盘输入和磁盘读写 Assembly 外中断 Assembly 端口 Assembly int指令 Assembly 内中断 Assembly 标志寄存器 Assembly 转移指令的原理 Assembly Call和ret指令 Assembly 数据处理两个基本问题 Assembly 灵活定位内存地址 Assembly 包含多个段的程序 Assembly [bx] loop Assembly 第一个程序 Assembly 寄存器 (内存访问) Assembly 寄存器 AWS VPN with EC2 hidden file in picture(linux) Assembly 基础 idea shortcuts 常用快捷键 idea plugin folder install ruby and jekyll

块设备驱动

2015年05月06日

###块设备驱动程序

回忆字符设备:

小孩在屋里睡觉,妈妈想知道小孩是否睡醒

  1. 查询方式,不停的开门查看,太累

  2. 休眠/唤醒,妈妈也进屋子里去休息,小孩睡醒后唤醒妈妈

  3. poll机制,加一个闹钟代表超时时间,如果小孩一直睡,闹钟超时后就会返回

  4. 异步通知(发信号),小孩睡醒后,开门通知妈妈

    以上4点都是使用自己的代码,不通用

  5. 输入子系统,融入别人的代码(别人帮我们完成了1、2、3、4)


###块设备驱动框架:


app: open,read,write "1.txt"
----------------------------------------文件的读写
文件系统:vfat,ext2,ext3,yaffs2,jffs2   (把文件的读写转换为扇区的读写)
----------------ll_rw_block-------------扇区的读写
                                    1.把"读写"放入队列
                                    2.调用队列的处理函数(优化/调顺序/合并)
               块设备驱动程序
----------------------------------------
硬件:硬盘,flash

详情参见《Linux内核源代码情景分析》


####分析ll_rw_block:

          for (i = 0; i < nr; i++) {
                    struct buffer_head *bh = bhs[i];
                              submit_bh(WRITE, bh);
                                        struct bio *bio;     //使用bh来构造bio (block input/output)
                                        submit_bio(rw, bio);
                                                  //通用的构造请求:使用bio来构造请求(request)
                                                  generic_make_request(bio);
                                                            __generic_make_request(bio);
                                                                      request_queue_t *q = bdev_get_queue(bio->bi_bdev);//找到队列
                                                                     
                                                                      //调用队列的"构造请求函数"
                                                                      ret = q->make_request_fn(q, bio);
                                                                                //默认的函数是__make_request
                                                                                __make_request
                                                                                          //先尝试合并(电梯算法)
                                                                                          elv_merge(q, &req, bio);
                                                                                         
                                                                                          //如果合并不成,使用bio构造请求
                                                                                          init_request_from_bio(req, bio);
                                                                                         
                                                                                          //把请求放入队列
                                                                                          add_request(q, req);
                                                                                         
                                                                                          //执行队列
                                                                                          __generic_unplug_device(q);
                                                                                         
                                                                                          //调用队列的"处理函数"
                                                                                          q->request_fn(q);
                                                                                         

###怎么写块设备驱动程序呢?

  1. 分配gendisk:alloc_disk
  2. 设置

    2.1 分配/设置队列:request_queue_t //它提供读写能力 blk_init_queue

    2.2 设置gendisk其他信息 //它提供属性:比如容量

  3. 注册:add_disk

####参考: drivers/block/xd.c

drivers/block/z2ram.c


ls /dev/sd* -l

次设备号为0时,表示整个磁盘。为1、2时,代表分区号


测试3th:

在开发板上:

  1. insmod ramblock.ko
  2. 格式化: mkdosfs /dev/ramblock
  3. 挂接: mount /dev/ramblock /tmp
  4. 读写文件: cd tmp 在里面操作文件
  5. cd / && umount /tmp
  6. cat /dev/ramblock > /mnt/ramblock.bin
  7. 在PC上查看ramblock.bin sudo mount -o loop ramblock.bin /mnt (loop 把一个普通文件当作块设备来挂接)

####写入不会立即写,要等一会才会写

# cp /etc/inittab /tmp/
do_ramblock_requset read 43
#
# do_ramblock_requset write 6
do_ramblock_requset write 7
do_ramblock_requset write 8
do_ramblock_requset write 9


写入不会立即写,一同步sync,则立即写
# cp /etc/init.d/rcS /tmp/
# sync
do_ramblock_requset write 10
do_ramblock_requset write 11
do_ramblock_requset write 12
do_ramblock_requset write 13
do_ramblock_requset write 14


写入不会立即写,umount时会完成写入
# cp /mnt/ramblock.ko /tmp
# cd /
# umount /tmp
do_ramblock_requset write 15
do_ramblock_requset write 16
do_ramblock_requset write 17
do_ramblock_requset write 18
do_ramblock_requset write 19
do_ramblock_requset write 20
do_ramblock_requset write 21
do_ramblock_requset write 22
do_ramblock_requset write 23
do_ramblock_requset write 24
do_ramblock_requset write 25
do_ramblock_requset write 26
do_ramblock_requset write 27
do_ramblock_requset write 28
do_ramblock_requset write 29
do_ramblock_requset write 30
do_ramblock_requset write 31
do_ramblock_requset write 32
do_ramblock_requset write 33
do_ramblock_requset write 34
do_ramblock_requset write 35
do_ramblock_requset write 36
do_ramblock_requset write 37
do_ramblock_requset write 38

实验:使用内存模拟硬盘,fdisk老工具,支持磁头柱面扇区,用getgeo模拟这些

测试5th:

  1. insmod ramblock.ko
  2. ls /dev/ramblock* -l
# ls /dev/ramblock* -l
brw-rw----    1 0        0        254,   0 Jan  1 00:42 /dev/ramblock

3. fdisk /dev/ramblock
4. ls /dev/ramblock* -l

# ls /dev/ramblock* -l
brw-rw----    1 0        0        254,   0 Jan  1 00:34 /dev/ramblock
brw-rw----    1 0        0        254,   1 Jan  1 00:36 /dev/ramblock1
brw-rw----    1 0        0        254,   2 Jan  1 00:36 /dev/ramblock2

fdisk这里分了2个分区,分别对其格式化

mkdosfs /dev/ramblock1
mkdosfs /dev/ramblock2

分别挂载2个分区

mount /dev/ramblock1 /mnt
mount /dev/ramblock2 /tmp

使用2个分区读写…