转载:谢谢原作者:块设备驱动实战基础篇三 (BIO请求回调机制)

1.5 块设备请求返回处理回调机制

 

本节我们继续完善1.4节中的代码,在上节我们完成了请求的过滤转发,那么请求被磁盘处理完成后返回回来的路径处理是怎样的,本节我们继续带着这样的问题再一次完善我们的驱动程序,通过本节的学习,我们能够真正掌握请求处理,转发过滤,请求完成后回调处理机制的完整学习。

 转载:谢谢原作者:块设备驱动实战基础篇三 (BIO请求回调机制)

先给出完善后的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: [email protected]

  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回调处理过程,我们先知道请求会通过我们注册的回调函数返回即可,后续再深入剖析操作系统细节。