您的位置:首页 > 其它

块设备驱动实战基础篇三 (BIO请求回调机制)

2014-01-06 20:22 363 查看

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回调处理过程,我们先知道请求会通过我们注册的回调函数返回即可,后续再深入剖析操作系统细节。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: