for (i = 0; i < nr; i++) {
struct buffer_head *bh = bhs[i];
submit_bh(rw, 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 /*
2 * 块设备驱动程序:内存用作磁盘
3 * 参考:
4 * .linux-2.6.22.6driverslockxd.c
5 * .linux-2.6.22.6driverslockz2ram.c
6 */
7
8 #include <linux/module.h>
9 #include <linux/errno.h>
10 #include <linux/interrupt.h>
11 #include <linux/mm.h>
12 #include <linux/fs.h>
13 #include <linux/kernel.h>
14 #include <linux/timer.h>
15 #include <linux/genhd.h>
16 #include <linux/hdreg.h>
17 #include <linux/ioport.h>
18 #include <linux/init.h>
19 #include <linux/wait.h>
20 #include <linux/blkdev.h>
21 #include <linux/blkpg.h>
22 #include <linux/delay.h>
23 #include <linux/io.h>
24
25 #include <asm/system.h>
26 #include <asm/uaccess.h>
27 #include <asm/dma.h>
28
29 /* 1M */
30 #define RAMBlock_SIZE (1024*1024)
31
32 static unsigned char *ramBlock_buf;
33
34 static struct gendisk *ramBlock_disk;
35 static request_queue_t *ramBlock_queue;
36
37 static int major;
38
39 /* 自旋锁 */
40 static DEFINE_SPINLOCK(ramBlock_lock);
41
42 //为了使用fdisk分区工具,假装自己是磁盘,
43 //有2个面,32个环,RAMBlock_SIZE/heads/cylinders/512个扇区
44 //容量:RAMBlock_SIZE = heads*cylinders*sectors*512
45 //1 disk = 2 heads
46 //1 heads = 32 cylinders
47 //1 cylinders = RAMBlock_SIZE/heads/cylinders/512 sectors = 32 sectors
48 static int ramBlock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
49 {
50 geo->heads = 2;
51 geo->cylinders = 32;
52 geo->sectors = 32;
53 return 0;
54 }
55
56
57 static struct block_device_operations ramBlock_fops = {
58 .owner = THIS_MODULE,
59 .getgeo = ramBlock_getgeo,
60 };
61
62 static void do_ramBlock_request(request_queue_t *q)
63 {
64 static int r_cnt = 0;
65 static int w_cnt = 0;
66 struct request *req;
67
68 //以电梯调度算法,取出下一个请求
69 while ((req = elv_next_request(q)) != NULL) {
70 /* 6 读写 */
71 //数据传输三要素:源、目的、长度
72 //源/目的 (要操作第几个扇区)
73 unsigned long offset = req->sector << 9; //<< 9 相当于 * 512
74
75 //目的/源 (读、写缓冲区)
76 //req->buffer
77
78 //长度 (缓冲区长度(sector的倍数))
79 unsigned long len = req->current_nr_sectors << 9;
80
81 //读数据
82 if (rq_data_dir(req) == READ)
83 {
84 printk("do_ramblock_request read %d
", ++r_cnt);
85 memcpy(req->buffer, ramBlock_buf+offset, len);
86 }
87 else { //写数据
88 printk("do_ramblock_request read %d
", ++r_cnt);
89 memcpy(ramBlock_buf+offset, req->buffer, len);
90 }
91
92 /******** 6 end ********/
93 end_request(req, 1);
94 }
95 return;
96 }
97
98
99 /* 1 出入口函数 */
100 static int ramBlock_init(void)
101 {
102 /* 2 分配一个gendisk结构体 */
103 ramBlock_disk = alloc_disk(16); //次设备号个数:分区个数+1
104 /******** 2 end ********/
105
106 /* 3 设置 */
107 //3.1 分配/设置队列(提供读写功能)
108 ramBlock_queue = blk_init_queue(do_ramBlock_request, &ramBlock_lock);
109
110 //3.2 设置其他属性:如容量
111 ramBlock_disk->queue = ramBlock_queue;
112
113 major = register_blkdev(0, "ramBlock_disk"); //cat /proc/devices
114 ramBlock_disk->major = major;
115
116 ramBlock_disk->first_minor = 0;
117 sprintf(ramBlock_disk->disk_name, "ramBlock_disk");
118 ramBlock_disk->fops = &ramBlock_fops;
119 set_capacity(ramBlock_disk, RAMBlock_SIZE/512); //第二个参数表示扇区个数,相对于内核而言,一个扇区为512字节
120 /******** 3 end ********/
121
122 /*
123 * 除了第4、第6、及以后的操作外,实际已经完成了块设备驱动框架的编写;
124 */
125
126 /* 4 硬件相关的操作 */
127 ramBlock_buf = kzalloc(RAMBlock_SIZE, GFP_KERNEL);
128 /******** 4 end ********/
129
130 /* 5 注册 */
131 add_disk(ramBlock_disk);
132 /******** 5 end ********/
133 return 0;
134 }
135
136
137 static void ramBlock_exit(void)
138 {
139 unregister_blkdev(major, "ramBlock_disk");
140 del_gendisk(ramBlock_disk);
141 put_disk(ramBlock_disk);
142 blk_cleanup_queue(ramBlock_queue);
143 kfree(ramBlock_buf);
144 return;
145 }
146
147 module_init(ramBlock_init);
148 module_exit(ramBlock_exit);
149 MODULE_LICENSE("GPL");
150 /******** 1 end ********/
调试
1. insmod ramBlock.ko
2. 格式化:
mkdosfs /dev/ramBlock_disk
3. 挂接:
mount /dev/ramBlock_disk /tmp
4. 读写文件:
cd /tmp
vi 1.txt
(分区:fdisk /dev/ramBlock_disk)
5. 卸载
cd /
umount /tmp/
6. 把/dev/ramBlock_disk目录下的文件,以镜像的形式保存到/mnt下
cat /dev/ramBlock_disk > /mnt/ramBlock_disk.bin
7. 在PC上查看ramBlock_disk.bin(把ramBlock_disk.bin作为回环设备挂接到/mnt)
sudo mount -o loop ramBlock_disk.bin /mn