服务器之家:专注于服务器技术及软件下载分享
分类导航

Linux|Centos|Ubuntu|系统进程|Fedora|注册表|Bios|Solaris|Windows7|Windows10|Windows11|windows server|

服务器之家 - 服务器系统 - Linux - Linux 块设备驱动代码编写

Linux 块设备驱动代码编写

2022-03-07 16:51feixiaoxing Linux

这篇文章主要介绍了Linux 块设备驱动代码编写,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

按照ldd的说法,linux的设备驱动包括了char,block,net三种设备。char设备是比较简单的,只要分配了major、minor号,就可以进行读写处理了。相对而言,block和net要稍微复杂些。net设备姑且按下不谈,我们在以后的博文中会有涉及。今天,我们可以看看一个简单的block是怎么设计的。

为了将block和fs分开,kernel的设计者定义了request queue这一种形式。换一句话说,所有fs对block设备的请求,最终都会转变为request的形式。所以,对于block设备驱动开发的朋友来说,处理好了request queue就掌握了block设备的一半。当然,block设备很多,hd、floppy、ram都可以这么来定义,有兴趣的朋友可以在drivers/block寻找相关的代码来阅读。兴趣没有那么强的同学,可以看看我们这篇博文,基本上也能学个大概。有个基本的概念,再加上一个简单浅显的范例,对于一般的朋友来说,已经足够了。

闲话不多说,我们看看一个ramdisk代码驱动是怎么写的,代码来自《深入linux 设备驱动程序内核机制》,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
 
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/vmalloc.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
 
#define RAMHD_NAME "ramhd"
#define RAMHD_MAX_DEVICE 2
#define RAMHD_MAX_PARTITIONS 4
 
#define RAMHD_SECTOR_SIZE 512
#define RAMHD_SECTORS 16
#define RAMHD_HEADS 4
#define RAMHD_CYLINDERS 256
 
#define RAMHD_SECTOR_TOTAL (RAMHD_SECTORS * RAMHD_HEADS *RAMHD_CYLINDERS)
#define RAMHD_SIZE (RAMHD_SECTOR_SIZE * RAMHD_SECTOR_TOTAL) //8mb
 
typedef struct {
  unsigned char* data;
  struct request_queue* queue;
  struct gendisk* gd;
}RAMHD_DEV;
 
static char* sdisk[RAMHD_MAX_DEVICE] = {NULL};
static RAMHD_DEV* rdev[RAMHD_MAX_DEVICE] = {NULL};
 
static dev_t ramhd_major;
 
static int ramhd_space_init(void)
{
  int i;
  int err = 0;
  for(i = 0; i < RAMHD_MAX_DEVICE; i++){
    sdisk[i] = vmalloc(RAMHD_SIZE);
    if(!sdisk[i]){
      err = -ENOMEM;
      return err;
    }
     
    memset(sdisk[i], 0, RAMHD_SIZE);
  }
   
  return err;
}
 
static void ramhd_space_clean(void)
{
  int i;
  for(i = 0; i < RAMHD_MAX_DEVICE; i++){
    vfree(sdisk[i]);
  }
}
 
static int ramhd_open(struct block_device* bdev, fmode_t mode)
{
  return 0;
}
 
static int ramhd_release(struct gendisk*gd, fmode_t mode)
{
  return 0;
}
 
static int ramhd_ioctl(struct block_device* bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
{
  int err;
  struct hd_geometry geo;
   
  switch(cmd)
  {
    case HDIO_GETGEO:
      err = !access_ok(VERIFY_WRITE, arg, sizeof(geo));
      if(err)
        return -EFAULT;
         
      geo.cylinders = RAMHD_CYLINDERS;
      geo.heads = RAMHD_HEADS;
      geo.sectors = RAMHD_SECTORS;
      geo.start = get_start_sect(bdev);
       
      if(copy_to_user((void*)arg, &geo, sizeof(geo)))
        return -EFAULT;
       
      return 0;
  }
   
  return -ENOTTY;
}
 
static struct block_device_operations ramhd_fops = {
  .owner = THIS_MODULE,
  .open = ramhd_open,
  .release = ramhd_release,
  .ioctl = ramhd_ioctl,
};
 
static int ramhd_make_request(struct request_queue* q, struct bio* bio)
{
  char* pRHdata;
  char* pBuffer;
  struct bio_vec* bvec;
  int i;
  int err = 0;
   
  struct block_device* bdev = bio->bi_bdev;
  RAMHD_DEV* pdev = bdev->bd_disk->private_data;
   
  if(((bio->bi_sector * RAMHD_SECTOR_SIZE) + bio->bi_size) > RAMHD_SIZE){
    err = -EIO;
    return err;
  }
   
  pRHdata = pdev->data + (bio->bi_sector * RAMHD_SECTOR_SIZE);
  bio_for_each_segment(bvec, bio, i){
    pBuffer = kmap(bvec->bv_page) + bvec->bv_offset;
    switch(bio_data_dir(bio)){
      case READ:
        memcpy(pBuffer, pRHdata, bvec->bv_len);
        flush_dcache_page(bvec->bv_page);
        break;
         
      case WRITE:
        flush_dcache_page(bvec->bv_page);
        memcpy(pRHdata, pBuffer, bvec->bv_len);
        break;
         
      default:
        kunmap(bvec->bv_page);
        goto out;
    }
     
    kunmap(bvec->bv_page);
    pRHdata += bvec->bv_len;
  }
   
out:
  bio_endio(bio, err);
  return 0;
}
 
static int alloc_ramdev(void)
{
  int i;
  for(i = 0; i < RAMHD_MAX_DEVICE; i++){
    rdev[i] = kzalloc(sizeof(RAMHD_DEV), GFP_KERNEL);
    if(!rdev[i]){
      return -ENOMEM;
    }
  }
   
  return 0;
}
 
static void clean_ramdev(void)
{
  int i;
   
  for(i = 0; i < RAMHD_MAX_DEVICE; i++){
    if(rdev[i])
      kfree(rdev[i]);
  }
}
 
static int __init ramhd_init(void)
{
  int i;
   
  ramhd_space_init();
  alloc_ramdev();
   
  ramhd_major = register_blkdev(0, RAMHD_NAME);
   
  for(i = 0; i < RAMHD_MAX_DEVICE; i++){
    rdev[i]->data = sdisk[i];
    rdev[i]->queue = blk_alloc_queue(GFP_KERNEL);
    blk_queue_make_request(rdev[i]->queue, ramhd_make_request);
     
    rdev[i]->gd = alloc_disk(RAMHD_MAX_PARTITIONS);
    rdev[i]->gd->major = ramhd_major;
    rdev[i]->gd->first_minor = i * RAMHD_MAX_PARTITIONS;
    rdev[i]->gd->fops = &ramhd_fops;
    rdev[i]->gd->queue = rdev[i]->queue;
    rdev[i]->gd->private_data = rdev[i];
    sprintf(rdev[i]->gd->disk_name, "ramhd%c", 'a' +i);
    rdev[i]->gd->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
    set_capacity(rdev[i]->gd, RAMHD_SECTOR_TOTAL);
    add_disk(rdev[i]->gd);
  }
   
  return 0;
}
 
static void __exit ramhd_exit(void)
{
  int i;
  for(i = 0; i < RAMHD_MAX_DEVICE; i++){
    del_gendisk(rdev[i]->gd);
    put_disk(rdev[i]->gd);
    blk_cleanup_queue(rdev[i]->queue);
  }
   
  clean_ramdev();
  ramhd_space_clean();
  unregister_blkdev(ramhd_major, RAMHD_NAME);
}
 
module_init(ramhd_init);
module_exit(ramhd_exit);
 
MODULE_AUTHOR("dennis__chen@ AMDLinuxFGL");
MODULE_DESCRIPTION("The ramdisk implementation with request function");
MODULE_LICENSE("GPL");

为了大家方便,顺便也把Makefile放出来,看过前面blog的朋友都知道,这其实很简单,

?
1
2
3
4
5
6
7
8
9
10
11
12
ifneq ($(KERNELRELEASE),)
obj-m := ramdisk.o
 
else
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
  $(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
  rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.* Module.*
endif

这段代码究竟有没有用呢?可以按照下面的步骤来做,

    a)make 一下,生成ramdisk.ko;

    b)编译好了之后,就可以安装驱动了,在linux下是这么做的,sudo insmod ramdisk.ko;

    c)安装好了,利用ls /dev/ramhd*, 就会发现在/dev下新增两个结点,即/dev/ramhda和/dev/ramhdb;

    d)不妨选择其中一个节点进行分区处理, sudo fdisk /dev/ramhda,简单处理的话就建立一个分区, 生成/dev/ramhda1;

    e)创建文件系统,sudo mkfs.ext3 /dev/ramhda1;

    f)有了上面的文件系统,就可以进行mount处理,不妨sudo mount /dev/ramhda1 /mnt;

    g)上面都弄好了,大家就可以copy、delete文件试试了,是不是很简单。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/feixiaoxing/article/details/11701797

延伸 · 阅读

精彩推荐
  • LinuxLinux中RPM文件操作的常用命令总结

    Linux中RPM文件操作的常用命令总结

    这篇文章主要给大家介绍了关于Linux中RPM文件操作的常用命令,文中通过示例介绍的很详细,对大家的理解和学习很有帮助,有需要的朋友们可以参考借鉴...

    Linux教程网11392021-11-30
  • Linuxlinux系统托盘不断闪烁之解决方法

    linux系统托盘不断闪烁之解决方法

    红旗6sp1虽然升级了一些配置和软件,但是也出现很多问题 比较突出的就是 当通过 网络 设置 一个pppoe adsl 上网以后,系统托盘不停的闪烁...

    Linux教程网2412020-06-19
  • Linux手把手教你分析 Linux 启动流程

    手把手教你分析 Linux 启动流程

    本文主要讲解当从 bootloader 跳转到 Linux 系统的启动函数 start_kernel 后,此函数对系统初始化的流程。...

    嵌入式Linux系统开发5002021-09-19
  • LinuxLinux 用cp和rsync同步文件时跳过指定目录的方法

    Linux 用cp和rsync同步文件时跳过指定目录的方法

    某测试站点,在某个节点的时候需要同步到正式站点去,但是里面的config目录不能覆盖,本文就来讲讲Linux 用cp和rsync同步文件时跳过指定目录的方法...

    Linux教程网5332020-11-19
  • LinuxLinux 系统查看磁盘可用空间的五个命令

    Linux 系统查看磁盘可用空间的五个命令

    工作中,经常会遇到磁盘爆满的情况,尤其是一台服务器运行了 N 年之后,里面会充满各种各样垃圾文件,比如:编译产生的中间文件、打包的镜像文件、...

    良许Linux9072022-01-05
  • Linuxlinux下安装ffmpeg的详细教程

    linux下安装ffmpeg的详细教程

    这篇文章主要介绍了linux下安装ffmpeg的详细教程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    ZT199442572020-07-16
  • LinuxLinux上超酷的命令行扩展工具Oh My Zsh

    Linux上超酷的命令行扩展工具Oh My Zsh

    这篇文章主要介绍了Linux上一个超酷的命令行扩展工具Oh My Zsh的相关使用,Oh My Zsh可以与iTerm一起使用来增强命令行功能,需要的朋友可以参考下...

    开源中文社区5222019-07-07
  • Linuxlinux system函数深入理解

    linux system函数深入理解

    本文将详细介绍linux system函数的使用,需要了解的朋友可以参考下 ...

    Linux教程网13472019-12-13