转载:谢谢原作者:块设备驱动实战基础篇三 (BIO请求回调机制)
1.5 塊設備請求返回處理回調機制
?
本節我們繼續完善1.4節中的代碼,在上節我們完成了請求的過濾轉發,那么請求被磁盤處理完成后返回回來的路徑處理是怎樣的,本節我們繼續帶著這樣的問題再一次完善我們的驅動程序,通過本節的學習,我們能夠真正掌握請求處理,轉發過濾,請求完成后回調處理機制的完整學習。
?
先給出完善后的IO架構圖,我們對比一下1.4節最后給出的圖有何區別:
?
相比1.4節,在fbd_driver框圖右側增加了fbd_driver end io function處理模塊,底層設備sd#的請求返回后,進入fbd_driver的請求回調處理函數中。我們再次貼一下完善后的代碼。
?
? 1 #ifndef?_FBD_DRIVER_H
? 2 #define?_FBD_DRIVER_H
? 3 #include <linux/init.h>
? 4 #include <linux/module.h>
? 5 #include <linux/blkdev.h>
? 6 #include <linux/bio.h>
? 7 #include <linux/genhd.h>
? 8
? 9 #define SECTOR_BITS???????????? (9)
?10 #define DEV_NAME_LEN??? ????????32
?11
?12 #define DRIVER_NAME???????????? "filter driver"
?13
?14 #define DEVICE1_NAME??????????? "fbd1_dev"
?15 #define DEVICE1_MINOR?????????? 0
?16 #define DEVICE2_NAME??????????? "fbd2_dev"
?17 #define DEVICE2_MINOR?????????? 1
?18
?19 struct fbd_dev {
?20????????struct request_queue *queue;
?21????????struct gendisk *disk;
?22????????sector_t size;????????? /* devicesize in Bytes */
?23????????char lower_dev_name[DEV_NAME_LEN];
?24????????struct block_device *lower_bdev;
?25 };
?26
?27 struct bio_context {
?28????????void *old_private;
?29????????void *old_callback;
?30 };
?31 #endif
?
? 1 /**
? 2?*? fbd-driver - filter blockdevice driver
? 3?*? Author: Talk@studio
? 4 **/
? 5 #include "fbd_driver.h"
? 6
? 7 static int fbd_driver_major = 0;
? 8
? 9 static struct fbd_dev fbd_dev1 =
?10 {
?11????????.queue = NULL,
?12????????.disk = NULL,
?13????????.lower_dev_name = "/dev/sdb",
?14????????.lower_bdev = NULL,
?15????????.size = 0
?16 };
?17
?18 static struct fbd_dev fbd_dev2 =
?19 {
?20????????.queue = NULL,
?21????????.disk = NULL,
?22????????.lower_dev_name = "/dev/sdc",
?23????????.lower_bdev = NULL,
?24????????.size = 0
?25 };
?26
?27 static int fbddev_open(struct inode *inode,struct file *file);
?28 static int fbddev_close(struct inode*inode, struct file *file);
?29
?30 static struct block_device_operationsdisk_fops = {
?31????????.open = fbddev_open,
?32????????.release = fbddev_close,
?33????????.owner = THIS_MODULE,
?34 };
?35
?36 static int fbddev_open(struct inode *inode,struct file *file)
37 {
?38????????printk("device is opened by:[%s]\n", current->comm);
?39????????return 0;
?40 }
?41
?42 static int fbddev_close(struct inode*inode, struct file *file)
?43 {
?44????????printk("device is closed by:[%s]\n", current->comm);
?45????????return 0;
?46 }
?47
?48 static int fbd_io_callback(struct bio *bio,unsigned int bytes_done, int error)
?49 {
?50????????struct bio_context *ctx = bio->bi_private;
?51
?52????????bio->bi_private = ctx->old_private;
?53????????bio->bi_end_io = ctx->old_callback;
?54????????kfree(ctx);
?55
?56????????printk("returned [%s] io request, end on sector %llu!\n",
?57???????????????? bio_data_dir(bio) == READ ?"read" : "write",
?58???????????????? bio->bi_sector);
?59
?60????????if (bio->bi_end_io) {
?61???????????????? bio->bi_end_io(bio,bytes_done, error);
?62????????}
?63
?64????????return 0;
?65 }
?66
?67 static int make_request(structrequest_queue *q, struct bio *bio)
?68 {
?69????????struct fbd_dev *dev = (struct fbd_dev *)q->queuedata;
?70????????struct bio_context *ctx;
?71
?72????????printk("device [%s] recevied [%s] io request, "
73???????????????? "access on dev sector[%llu], length is [%u] sectors.\n",
?74???????????????? dev->disk->disk_name,
?75 ????????????????bio_data_dir(bio) == READ ?"read" : "write",
?76???????????????? bio->bi_sector,
?77???????????????? bio_sectors(bio));
?78
?79????????ctx = kmalloc(sizeof(struct bio_context), GFP_KERNEL);
?80????????if (!ctx) {
?81???????????????? printk("alloc memory forbio_context failed!\n");
?82???????????????? bio_endio(bio,bio->bi_size, -ENOMEM);
?83???????????????? goto out;
?84????????}
?85????????memset(ctx, 0, sizeof(struct bio_context));
?86
?87????????ctx->old_private = bio->bi_private;
?88????????ctx->old_callback = bio->bi_end_io;
?89????????bio->bi_private = ctx;
?90????????bio->bi_end_io = fbd_io_callback;
?91
?92????????bio->bi_bdev = dev->lower_bdev;
?93????????submit_bio(bio_rw(bio), bio);
?94 out:
?95????????return 0;
?96 }
?97
?98 static int dev_create(struct fbd_dev *dev,char *dev_name, int major, int minor)
?99 {
100???????? int ret = 0;
101
102???????? /* init fbd_dev */
103???????? dev->disk = alloc_disk(1);
104???????? if (!dev->disk) {
105???????????????? printk("alloc diskerror");
106???????????????? ret = -ENOMEM;
107???????????????? goto err_out1;
108???????? }
109
110???????? dev->queue =blk_alloc_queue(GFP_KERNEL);
111???????? if (!dev->queue) {
112???????????????? printk("alloc queueerror");
113??????? ?????????ret = -ENOMEM;
114???????????????? goto err_out2;
115???????? }
116
117???????? /* init queue */
118???????? blk_queue_make_request(dev->queue,make_request);
119???????? dev->queue->queuedata = dev;
120
121???????? /* init gendisk */
122?????? ??strncpy(dev->disk->disk_name, dev_name,DEV_NAME_LEN);
123???????? dev->disk->major = major;
124???????? dev->disk->first_minor = minor;
125???????? dev->disk->fops =&disk_fops;
126
127???????? dev->lower_bdev =open_bdev_excl(dev->lower_dev_name, FMODE_WRITE | FMODE_READ,dev->lower_bdev);
128???????? if (IS_ERR(dev->lower_bdev)) {
129???????????????? printk("Open thedevice[%s]'s lower dev [%s] failed!\n", dev_name, dev->lower_dev_name);
130???????????????? ret = -ENOENT;
131???????????????? goto err_out3;
132???????? }
133
134???????? dev->size =get_capacity(dev->lower_bdev->bd_disk) << SECTOR_BITS;
135
136???????? set_capacity(dev->disk,(dev->size >> SECTOR_BITS));
137
138???????? /* bind queue to disk */
139???????? dev->disk->queue = dev->queue;
140
141???????? /* add disk to kernel */
142???????? add_disk(dev->disk);
143???????? return 0;
144err_out3:
145???????? blk_cleanup_queue(dev->queue);
146err_out2:
147???????? put_disk(dev->disk);
148err_out1:
149???????? return ret;
150 }
151
152 staticvoid dev_delete(struct fbd_dev *dev, char *name)
153 {
154???????? printk("delete the device[%s]!\n", name);
155???????? close_bdev_excl(dev->lower_bdev);
156
157???????? blk_cleanup_queue(dev->queue);
158???????? del_gendisk(dev->disk);
159???? ????put_disk(dev->disk);
160 }
161
162 staticint __init fbd_driver_init(void)
163 {
164???????? int ret;
165
166???????? /* register fbd driver, get the drivermajor number*/
167???????? fbd_driver_major =register_blkdev(fbd_driver_major, DRIVER_NAME);
168???????? if (fbd_driver_major < 0) {
169???????????????? printk("get majorfail");
170???????????????? ret = -EIO;
171???????????????? goto err_out1;
172???????? }
173
174???????? /* create the first device */
175???????? ret = dev_create(&fbd_dev1, DEVICE1_NAME,fbd_driver_major, DEVICE1_MINOR);
176???????? if (ret) {
177???????????????? printk("create device[%s] failed!\n", DEVICE1_NAME);
178???????????????? goto err_out2;
179???????? }
180
181???????? /* create the second device */
182???????? ret = dev_create(&fbd_dev2,DEVICE2_NAME, fbd_driver_major, DEVICE2_MINOR);
183???????? if (ret) {
184???????????????? printk("create device[%s] failed!\n", DEVICE2_NAME);
185???????????????? goto err_out3;
186???????? }
187???????? return ret;
188err_out3:
189???????? dev_delete(&fbd_dev1,DEVICE1_NAME);
190err_out2:
191???????? unregister_blkdev(fbd_driver_major,DRIVER_NAME);
192err_out1:
193???????? return ret;
194 }
195
196 staticvoid __exit fbd_driver_exit(void)
197 {
198???????? /* delete the two devices */
199???????? dev_delete(&fbd_dev2,DEVICE2_NAME);
200???????? dev_delete(&fbd_dev1,DEVICE1_NAME);
201
202???????? /* unregister fbd driver */
203???????? unregister_blkdev(fbd_driver_major,DRIVER_NAME);
204???????? printk("block device driver exitsuccessfuly!\n");
205 }
206
207module_init(fbd_driver_init);
208module_exit(fbd_driver_exit);
209MODULE_LICENSE("GPL");
?
先看頭文件的變化,27-30行我們新定義了一個數據結構bio_context,顧名思義該數據結構用于描述bio請求的上下文信息,里面有兩個成員,都是指針,old_private指針用于保存bio中private指針內容,old_callback用于保存bio中舊的回調函數指針。
?
接下來分析fbd_driver.c,我們直接看make_request函數,67-96行。
?
67 staticint make_request(struct request_queue *q, struct bio *bio)
?68 {
?69????????struct fbd_dev *dev = (struct fbd_dev *)q->queuedata;
?70????????struct bio_context *ctx;
?71
?72????????printk("device [%s] recevied [%s] io request, "
?73???????????????? "access on dev sector[%llu], length is [%u] sectors.\n",
?74???????????????? dev->disk->disk_name,
?75???????????????? bio_data_dir(bio) == READ ?"read" : "write",
?76???????????????? bio->bi_sector,
?77???????????????? bio_sectors(bio));
?78
?79????????ctx = kmalloc(sizeof(struct bio_context), GFP_KERNEL);
?80 ????????if (!ctx) {
?81???????????????? printk("alloc memory forbio_context failed!\n");
?82???????????????? bio_endio(bio,bio->bi_size, -ENOMEM);
?83???????????????? goto out;
?84????????}
?85????????memset(ctx, 0, sizeof(struct bio_context));
?86
?87????????ctx->old_private = bio->bi_private;
?88????????ctx->old_callback = bio->bi_end_io;
?89????????bio->bi_private = ctx;
?90????????bio->bi_end_io = fbd_io_callback;
?91
?92????????bio->bi_bdev = dev->lower_bdev;
?93????????submit_bio(bio_rw(bio), bio);
?94 out:
?95????????return 0;
?96 }
?
?
70行定義了一個bio_context指針變量,79行通過kmalloc函數為ctx指針申請了內存并賦值,這樣我們申請bio的上下文信息數據結構,并在85行用memset函數將ctx數據結構清空,接下來87-88行,我們保存了bio中的bi_private指針和bi_end_io回調函數指針,在90-91行把bio中的這兩個指針重新賦值了,bi_private賦值為ctx指針值,bi_end_io回調函數指針賦值為fbd_io_callback函數指針,這樣我們完成了bio請求的再次加工處理,我們趁熱打鐵繼續分析fbd_io_callback函數一探究竟,搞清楚這么的做的原因。
?
?48 static int fbd_io_callback(struct bio *bio,unsigned int bytes_done, int error)
?49 {
?50????????struct bio_context *ctx = bio->bi_private;
?51
?52????????bio->bi_private = ctx->old_private;
?53????????bio->bi_end_io = ctx->old_callback;
?54????????kfree(ctx);
?55
?56????????printk("returned [%s] io request, end on sector %llu!\n",
?57???????????????? bio_data_dir(bio) == READ ?"read" : "write",
?58??? ?????????????bio->bi_sector);
?59
?60????????if (bio->bi_end_io) {
?61???????????????? bio->bi_end_io(bio,bytes_done, error);
?62????????}
?63
?64????????return 0;
?65 }
?
輸入參數是bio指針以及請求完成的子結束和錯誤標志,由于在90行我們把bio中bi_private的指針賦值到ctx指針中,這樣50行的代碼我們就可以重新獲取ctx指針,進而52-53行我們重新恢復bio的bi_private/bi_end_io指針值,最后54行釋放ctx,因為此時ctx中的指針值我們已恢復,ctx已不再有用可以釋放其占用的內存,我們繼續調用bio原本就注冊好的bi_end_io回調函數,完成真正的請求處理結束操作。
?
?????? 至此,我們走完了完整的請求處理,轉發過濾,完成回調全過程。
P.S.: 注意此篇并沒有深入剖析硬中斷->軟中斷->bio回調處理過程,我們先知道請求會通過我們注冊的回調函數返回即可,后續再深入剖析操作系統細節。
總結
以上是生活随笔為你收集整理的转载:谢谢原作者:块设备驱动实战基础篇三 (BIO请求回调机制)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 转载:谢谢原作者: 块设备驱动实战基础篇
- 下一篇: 转载:谢谢原作者:块设备驱动实战基础篇四