1.6介绍一种内核与用户空间通信的方法-misc设备ioctl机制

块设备驱动开发中往往需要配合用户态的管理程序工具,管理我们的块设备,此时我们需要涉及用户空间程序与块设备通信的方法,ioctl机制就是接下来需要学习和实战的,通过ioctl机制,用户态负责发送各种命令给内核驱动;内核态接收用户态发送的命令,并根据命令执行相应的动作,如下图所示。

ioctl提供用户态程序使用内核态函数的通道,此时需要注册一个字符设备来实现,我们使用misc这个字符设备来实现。

Ioctl.h

1 #ifndef _IOCTL_H

2 #define _IOCTL_H

3

4 /* misc device name*/

5 #define MISC_NAME "ioctl_test"

6

7 /**

8  *define ioctl codes for interfacing between kernel_module and user program

9  */

10 #define IOCTL_CODE      0xcc /* major type code - adjusted for target system */

11

12 #define TEST_CMD        _IOWR (IOCTL_CODE,  0x09, unsigned long)

13

14 #endif

user.c

1 #include <sys/ioctl.h>

2 #include <unistd.h>

3 #include <fcntl.h>

4 #include <stdio.h>

5 #include "ioctl.h"

6

7 int main(void)

8 {

9        unsigned long arg = 2013;

10        int fd;

11

12        fd = open("/dev/"MISC_NAME, O_RDWR, 0);

13        if (fd < 0) {

14                 printf("Failed to open/dev/%s\n", MISC_NAME);

15                 goto out;

16        }

17

18        if (ioctl(fd, TEST_CMD, &arg) < 0) {

19                 printf("Failed to executeioctl!\n");

20        }

21

22        close(fd);

23 out:

24        return 0;

25 }

kernel.c

1 /*

2  * IOCTL

3  *Author: talk@studio

4  */

5

6 #include <linux/fs.h>

7 #include <linux/uaccess.h>

8 #include <linux/module.h>

9 #include <linux/miscdevice.h>

10

11 #include "ioctl.h"

12

13 static int ioctl(struct inode *inode,struct file *file,

14                      unsigned int cmd,unsigned long user)

15 {

16        unsigned long arg;

17        int ret = 0;

18

19        if (_IOC_TYPE(cmd) != IOCTL_CODE) {

20                 printk("Unknown ioctlcommand 0x%x\n", cmd);

21                 ret = -ENOTTY;

22                 goto out;

23        }

24

25        switch (cmd) {

26                 case TEST_CMD:

27                         ret =copy_from_user(&arg, (unsigned long *)user, sizeof(unsigned lon    g));

28                        if (ret) {

29                                printk("copy from user failed!\n");

30                         } else {

31                                printk("received IOctl[arg=%lu] from user!\n", arg);

32                         }

33                         break;

34                 default:

35                         printk("Unknownioctl command[0x%x].\n", cmd);

36                         ret = -ENOTTY;

37                         break;

38        }

39 out:

40        return ret;

41 }

42

43 static struct file_operations_misc_ctl_fops = {

44        .ioctl = ioctl,

45        .owner = THIS_MODULE,

46 };

47

48 static struct miscdevice _misc_dev = {

49        .minor = MISC_DYNAMIC_MINOR,

50        .name = MISC_NAME,

51        .fops = &_misc_ctl_fops

52 };

53

54 static int __init ioctl_init(void)

55 {

56        int ret;

57

58        ret = misc_register(&_misc_dev);

59        if (ret) {

60                 printk("Register ioctldevice[%s] failed\n", _misc_dev.name);

61        }

62        return ret;

63 }

64

65 static void __exit ioctl_exit(void)

66 {

67        if (misc_deregister(&_misc_dev) < 0) {

68                 printk("Deregister ioctlcontrol device[%s] failed\n", _misc_dev.name);

69        }

70        return;

71 }

72

73 module_init(ioctl_init);

74 module_exit(ioctl_exit);

75 MODULE_LICENSE("GPL");

1.7逐渐成型 - 构件完善的管理工具及内核块设备驱动模块

经过上面四节的实战和学习,我们把代码完善一下,实现一个完整的用户态管理功能和内核块设备驱动的代码设计,我们需要完成如下功能,下图展示了我们程序各个模块的关系。

我们看一下代码如何实现,首先看公用头文件定义

fbd_ioctl.h

1 /*

2  *Author: talk@studio

3  */

4

5 #ifndef _IOCTL_H

6 #define _IOCTL_H

7

8 /* misc device name*/

9 #define MISC_NAME "fbd_misc_dev"

10

11 /* param structure for device create */

12 struct create_param {

13        char fbd_dev_name[32];

14        char lower_dev_path[64];

15 };

16

17 struct delete_param {

18        char fbd_dev_name[32];

19 };

20

21 /**

22  *define ioctl codes for interfacing between kernel_module and user program

23  */

24 #define IOCTL_CODE      0xcc /* major type code - adjusted for target system */

25

26 #define CREATE_CMD      _IOWR (IOCTL_CODE,  0x0A, struct create_param)

27 #define DELETE_CMD      _IOWR (IOCTL_CODE,  0x0B, struct delete_param)

28

29 #endif

用户态代码

1 /*

2  *Author: talk@studio

3  */

4

5 #include <sys/ioctl.h>

6 #include <unistd.h>

7 #include <fcntl.h>

8 #include <stdio.h>

9

10 #include"../common/include/fbd_ioctl.h"

11

12 int main(void)

13 {

14        int fd;

15        struct create_param ctr_param = {

16                 .fbd_dev_name ="fbd_dev1",

17                 .lower_dev_path = "/dev/sdb",

18        };

19

20        fd = open("/dev/"MISC_NAME, O_RDWR, 0);

21        if (fd < 0) {

22                 printf("Failed to open/dev/%s\n", MISC_NAME);

23                 goto out;

24        }

25

26        if (ioctl(fd, CREATE_CMD, &ctr_param) < 0) {

27                 printf("Failed to executeioctl!\n");

28        }

29

30        close(fd);

31 out:

32        return 0;

33 }

34

1 /*

2  *Author: talk@studio

3  */

4

5 #include <sys/ioctl.h>

6 #include <unistd.h>

7 #include <fcntl.h>

8 #include <stdio.h>

9

10 #include"../common/include/fbd_ioctl.h"

11

12 int main(void)

13 {

14        int fd;

15        struct delete_param del_param = {

16                 .fbd_dev_name ="fbd_dev1",

17        };

18

19        fd = open("/dev/"MISC_NAME, O_RDWR, 0);

20        if (fd < 0) {

21                 printf("Failed to open/dev/%s\n", MISC_NAME);

22                 goto out;

23        }

24

25        if (ioctl(fd, DELETE_CMD, &del_param) < 0) {

26                 printf("Failed to executeioctl!\n");

27        }

28

29        close(fd);

30 out:

31        return 0;

32 }

33

内核驱动代码

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 #include <linux/fs.h>

9 #include <linux/uaccess.h>

10 #include <linux/miscdevice.h>

11

12 #define SECTOR_BITS             (9)

13 #define DEV_NAME_LEN            32

14

15 #define DRIVER_NAME             "filter driver"

16

17 struct fbd_dev {

18        char fbd_dev_name[DEV_NAME_LEN];

19        struct request_queue *queue;

20        struct gendisk *disk;

21        sector_t size;          /* devicesize in Bytes */

22

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 #include "../common/include/fbd_ioctl.h"

7

8 static int fbd_driver_major = 0;

9

10 static struct fbd_dev fbd_dev =

11 {

12        .fbd_dev_name = "\0",

13        .queue = NULL,

14        .disk = NULL,

15        .lower_dev_name = "\0",

16        .lower_bdev = NULL,

17         .size = 0

18 };

19

20 static int fbddev_open(struct inode *inode,struct file *file);

21 static int fbddev_close(struct inode*inode, struct file *file);

22

23 static struct block_device_operationsdisk_fops = {

24        .open = fbddev_open,

25        .release = fbddev_close,

26        .owner = THIS_MODULE,

27 };

28

29 static int fbddev_open(struct inode *inode,struct file *file)

30 {

31        printk("device is opened by:[%s]\n", current->comm);

32        return 0;

33 }

34

35 static int fbddev_close(struct inode*inode, struct file *file)

36 {

37         printk("device is closedby:[%s]\n", current->comm);

38        return 0;

39 }

40

41 static int fbd_io_callback(struct bio *bio,unsigned int bytes_done, int error)

42 {

43        struct bio_context *ctx = bio->bi_private;

44

45        bio->bi_private = ctx->old_private;

46        bio->bi_end_io = ctx->old_callback;

47        kfree(ctx);

48

49        printk("returned [%s] io request, end on sector %llu!\n",

50                 bio_data_dir(bio) == READ ?"read" : "write",

51                 bio->bi_sector);

52

53        if (bio->bi_end_io) {

54                 bio->bi_end_io(bio,bytes_done, error);

55        }

56

57        return 0;

58 }

59

60 static int make_request(structrequest_queue *q, struct bio *bio)

61 {

62        struct fbd_dev *dev = (struct fbd_dev *)q->queuedata;

63        struct bio_context *ctx;

64

65        printk("device [%s] recevied [%s] io request, "

66                "access on devsector [%llu], length is [%u] sectors.\n",

67                 dev->disk->disk_name,

68                 bio_data_dir(bio) == READ ?"read" : "write",

69                 bio->bi_sector,

70                 bio_sectors(bio));

71

72        ctx = kmalloc(sizeof(struct bio_context), GFP_KERNEL);

73         if (!ctx) {

74                 printk("alloc memory forbio_context failed!\n");

75                 bio_endio(bio,bio->bi_size, -ENOMEM);

76                 goto out;

77         }

78        memset(ctx, 0, sizeof(struct bio_context));

79

80        ctx->old_private = bio->bi_private;

81        ctx->old_callback = bio->bi_end_io;

82        bio->bi_private = ctx;

83        bio->bi_end_io = fbd_io_callback;

84

85         bio->bi_bdev = dev->lower_bdev;

86        submit_bio(bio_rw(bio), bio);

87 out:

88        return 0;

89 }

90

91 static int dev_create(char *fbd_dev_name,char *lower_dev_path)

92 {

93        int ret = 0;

94        struct fbd_dev *dev = &fbd_dev;

95

96        if(fbd_dev.disk){

97                 printk("device[%s] isalready exist, delete it first!\n", fbd_dev.fbd_dev_nam    e);

98                 ret = -EEXIST;

99                 return ret;

100         }

101

102         dev->disk = alloc_disk(1);

103         if (!dev->disk) {

104                 printk("alloc diskerror");

105                 ret = -ENOMEM;

106                 goto err_out1;

107         }

108

109         dev->queue =blk_alloc_queue(GFP_KERNEL);

110         if (!dev->queue) {

111                 printk("alloc queueerror");

112                 ret = -ENOMEM;

113                 goto err_out2;

114         }

115

116         /* init queue */

117         blk_queue_make_request(dev->queue,make_request);

118         dev->queue->queuedata = dev;

119

120         /* init gendisk */

121         strncpy(dev->disk->disk_name,fbd_dev_name, DEV_NAME_LEN);

122         dev->disk->major =fbd_driver_major;

123         dev->disk->first_minor = 0;

124         dev->disk->fops = &disk_fops;

125

126         dev->lower_bdev =open_bdev_excl(lower_dev_path, FMODE_WRITE | FMODE_READ, dev->lower    _bdev);

127         if (IS_ERR(dev->lower_bdev)) {

128                 printk("Open thedevice[%s]'s lower dev [%s] failed!\n", fbd_dev_name, lower_    dev_path);

129                 ret = -ENOENT;

130                 goto err_out3;

131         }

132

133         dev->size =get_capacity(dev->lower_bdev->bd_disk) << SECTOR_BITS;

134

135         set_capacity(dev->disk,(dev->size >> SECTOR_BITS));

136

137         /* bind queue to disk */

138         dev->disk->queue =dev->queue;

139

140         /* add disk to kernel */

141         add_disk(dev->disk);

142

143         strncpy(dev->fbd_dev_name,fbd_dev_name, DEV_NAME_LEN);

144         strncpy(dev->lower_dev_name,lower_dev_path, DEV_NAME_LEN);

145         return 0;

146err_out3:

147         blk_cleanup_queue(dev->queue);

148err_out2:

149         put_disk(dev->disk);

150err_out1:

151         memset(&fbd_dev, 0, sizeof(structfbd_dev));

152         return ret;

153 }

154

155 staticint dev_delete(char *fbd_dev_name)

156 {

157         int ret = 0;

158         struct fbd_dev *dev = &fbd_dev;

159

160         if (strcmp(fbd_dev_name,dev->fbd_dev_name) == 0) {

161                 printk("delete the device[%s]!\n", fbd_dev_name);

162                close_bdev_excl(dev->lower_bdev);

163                 del_gendisk(dev->disk);

164                 put_disk(dev->disk);

165                blk_cleanup_queue(dev->queue);

166                 memset(&fbd_dev, 0,sizeof(struct fbd_dev));

167         } else {

168                 printk("device[%s] isn'texist!\n", fbd_dev_name);

169                 ret = -EEXIST;

170         }

171         return ret;

172 }

173

174 staticint ioctl(struct inode *inode, struct file *file,

175                      unsigned int cmd,unsigned long user)

176 {

177         struct delete_param del_param;

178         struct create_param ctr_param;

179         int ret = 0;

180

181         if (_IOC_TYPE(cmd) != IOCTL_CODE) {

182                 printk("Unknown ioctl command0x%x\n", cmd);

183                 ret = -ENOTTY;

184                 goto out;

185         }

186

187         switch (cmd) {

188                 case CREATE_CMD:

189                         ret =copy_from_user(&ctr_param, (void *)user, sizeof(struct create_p    aram));

190                         if (ret) {

191                                printk("copy from user failed!\n");

192                         } else {

193                                 ret = dev_create(ctr_param.fbd_dev_name,ctr_param.lower_dev_    path);

194                         }

195                         break;

196                 case DELETE_CMD:

197                         ret =copy_from_user(&del_param, (void *)user, sizeof(struct delete_p    aram));

198                         if (ret) {

199                                printk("copy from user failed!\n");

200                         } else {

201                                 ret =dev_delete(del_param.fbd_dev_name);

202                         }

203                         break;

204                 default:

205                         printk("Unknownioctl command[0x%x].\n", cmd);

206                         ret = -ENOTTY;

207                         break;

208         }

209 out:

210         return ret;

211 }

212

213 staticstruct file_operations _misc_ctl_fops = {

214         .ioctl = ioctl,

215         .owner = THIS_MODULE,

216 };

217

218 staticstruct miscdevice _misc_dev = {

219         .minor = MISC_DYNAMIC_MINOR,

220         .name = MISC_NAME,

221         .fops = &_misc_ctl_fops

222 };

223

224 staticint __init fbd_driver_init(void)

225 {

226         int ret;

227

228         /* register fbd driver, get the drivermajor number*/

229         fbd_driver_major = register_blkdev(fbd_driver_major,DRIVER_NAME);

230         if (fbd_driver_major < 0) {

231                 printk("get majorfail");

232                 ret = -EIO;

233                 goto err_out1;

234         }

235

236         ret = misc_register(&_misc_dev);

237         if (ret) {

238                 printk("Register ioctldevice[%s] failed\n", _misc_dev.name);

239                 goto err_out2;

240         }

241

242         printk("block device driver initsuccessfuly!\n");

243         return ret;

244err_out2:

245         unregister_blkdev(fbd_driver_major,DRIVER_NAME);

246err_out1:

247         return ret;

248 }

249

250 staticvoid __exit fbd_driver_exit(void)

251 {

252         if(fbd_dev.disk){

253                 printk("device[%s] isalready exist, delete it first!\n", fbd_dev.fbd_dev_nam    e);

254                dev_delete(fbd_dev.fbd_dev_name);

255         }

256

257         if(misc_deregister(&_misc_dev)< 0) {

258                 printk("Deregister ioctlcontrol device[%s] failed\n", _misc_dev.name);

259         }

260

261         /* unregister fbd driver */

262         unregister_blkdev(fbd_driver_major,DRIVER_NAME);

263         printk("block device driver exitsuccessfuly!\n");

264 }

265

266module_init(fbd_driver_init);

267module_exit(fbd_driver_exit);

268MODULE_LICENSE("GPL");

转载:谢谢原作者:块设备驱动实战基础篇四 (逐渐成型,加入ioctl通信机制)相关推荐

  1. 转载:谢谢原作者: 块设备驱动实战基础篇二 (继续完善170行过滤驱动代码至200行)

    1.3块设备驱动关键数据结构及函数API详细剖析 经过上节四个步骤我们已经熟悉并实战了一个最基本的过滤块设备驱动的设计技巧,我们这一节先不继续实战,我们本节把上节170行代码中接触到的块设备核心数据结 ...

  2. 转载:谢谢原作者:块设备驱动实战基础篇一 (170行代码构建一个逻辑块设备驱动)

    1   内核块设备驱动基础学习与实战 1.1 设备驱动IO架构初探 操作系统是如何将数据读到缓冲区的,发生了什么?我们带着这样的问题,粗略走一下read调用系统过程,希望这个初探,可以唤起大家研究操作 ...

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

    1.5 块设备请求返回处理回调机制 本节我们继续完善1.4节中的代码,在上节我们完成了请求的过滤转发,那么请求被磁盘处理完成后返回回来的路径处理是怎样的,本节我们继续带着这样的问题再一次完善我们的驱动 ...

  4. linux块设备驱动编写,Linux内核学习笔记 -49 工程实践-编写块设备驱动的基础

    块设备可以随机存储.字符设备,比如键盘,只能按照输入顺序存取,不可随机,打乱输入的字节流. 文件系统层,包括常见的文件系统,以及虚拟文件系统层VFS,字符设备可以直接用应用程序打开.块设备不会在应用程 ...

  5. Linux 字符设备驱动开发基础(四)—— ioctl() 函数解析

    解析完 open.close.read.write 四个函数后,终于到我们的 ioctl() 函数了 一. 什么是ioctl ioctl是设备驱动程序中对设备的I/O通道进行管理的函数.所谓对I/O通 ...

  6. 块设备驱动、bio理解

    别人写过的内容,我就不写了.贴一下大佬的博客,写的非常好: 块设备驱动实战基础篇一 (170行代码构建一个逻辑块设备驱动) 块设备驱动实战基础篇二 (继续完善170行过滤驱动代码至200行) 块设备驱 ...

  7. Nginx实战基础篇六 通过源码包编译安装部署LNMP搭建Discuz论坛

    Nginx实战基础篇六 通过源码包编译安装部署LNMP搭建Discuz论坛 版权声明: 本文遵循"署名非商业性使用相同方式共享 2.5 中国大陆"协议 您可以自由复制.发行.展览. ...

  8. Nginx实战基础篇一 源码包编译安装部署web服务器

    Nginx实战基础篇一 源码包编译安装部署web服务器 版权声明: 本文遵循"署名非商业性使用相同方式共享 2.5 中国大陆"协议 您可以自由复制.发行.展览.表演.放映.广播或通 ...

  9. 转:写一个块设备驱动

    ----------------------- Page 1----------------------- 第 1章 +---------------------------------------- ...

最新文章

  1. Powercli 批量获取vmhost 时间
  2. Nginx防盗链与访问控制
  3. OpenCV3编程入门(毛星云)之视频读取与播放
  4. gis中dbf转为csv_Python中.dbf到.csv的批量转换
  5. 工具 - MyEclipse算法机最新8.6forSpring有效
  6. 转wordpress小工具制作前台后台全解析
  7. 【渝粤教育】21秋期末考试马克思主义基本原理概论(A)10882k1 (2)
  8. python 裁判文书网_python - 用selenium模拟登陆裁判文书网,系统报错找不到元素。...
  9. vscode浏览器扩展(图文教程) - 设置篇
  10. 枚举算法:求两个整数m,n(m>n)最大公约数的欧几里得算法描述。
  11. 对前后端分离和FastDFS的使用的再理解
  12. vim编辑时遇到E325: ATTENTION Found a swap file by the name ./.backu.sh.swp错误代码的解决办法
  13. 滴滴这名员工的N+1飞了,离职带走公司文档
  14. nginx配置文件服务器
  15. Atitit 作用域的理解attilax总结 1.1. 作用域是指对某一变量和方法具有访问权限的代码空间, 1 1.2. 作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突。 1 1
  16. 89c51交通灯汇编语言程序,89C51单片机交通灯汇编程序
  17. DELL D630 显卡门事件 终于碰上了~
  18. [从零开始学习FPGA编程-22]:进阶篇 - 架构 - FPGA内部硬件电路的设计与建模
  19. javascript 表单提交和验证的方法
  20. 线性代数笔记1.1n阶行列式

热门文章

  1. 西安电子科技大学计算机接口与通用技术答案,西安电子科技大学--西电《计算机接口与通信技术》平时作业...
  2. 温铁军、林毅夫、陈平,从学术、现实等多方面来分析,谁的价值高?
  3. 激光点云感知 voxnet本质
  4. 计算机组成801pan,计算机组成06801.ppt
  5. python循环输入字典_python - 使用'for'循环迭代字典
  6. Python入门100题 | 第061题
  7. Python入门100题 | 第024题
  8. 支付宝扫一下就能体验的深度学习模型
  9. Python中的if __name__ == ‘__main__‘
  10. Netty 学习和进阶策略