涉及到一个问题,在内核态读磁盘固定的位置的数据应该怎么办。如果是在用户态,有C库函数可以做到,read, lseek 等都可以。但是在内核态呢?最直接的办法就是自己发bio去读,但这样有点麻烦,还有两种比较简单的方法。
一种是用buffer_head, 一种是用 dm_io_sync_vm。
第一种:buffer_head.
代码如下:
22static int __init bread_init(void)
23 {
24
25 struct buffer_head *bh = NULL; //声明bh
26 struct block_device *bdev;
27 char *p, ch;
28 int i;
29 int block_size;
30 int j;
31
32 bdev = open_bdev_excl(PATH, FMODE_READ, NULL); //打开设备,获取bdev
33 if (IS_ERR(bdev)) {
34 printk(KERN_ALERT "open bdev failed./n");
35 goto out1;
36 }
37
38
39 block_size = bdev->bd_block_size;
40
42 bh = __bread(bdev, j, block_size);
43 if (bh == NULL) {
44 printk(KERN_ALERT "__bread error./n");
45 goto out2;
46 }
47
48 p = (char *)(bh->b_data);
49 printk(KERN_ALERT "%c", p[0]);
50 for (i = 0; i < block_size; i++) {
51 p[i] = ch;
52 }
53 printk(KERN_ALERT "/n");
54
55 set_buffer_uptodate(bh); //写回
56 mark_buffer_dirty(bh);
57
58 if (bh) {
59 brelse(bh);
60 }
61
62 return 0;
63 }
需要注意的问题:
1. bh只是声明,并没有为他分配空间。bh的查找似乎就是在内存中找一个,或者内核去分配,调用者不用去管。
2. 要将buffer_head写回的话,只需要 55, 56两行代码就可以了。剩下的由操作系统做的事情,我也不知道是什么。
第二种方法: dm_io_sync_vm
代码如下:
#include "dm.h"
#include "dm-io.h"
static int __init mydm_init(void)
{
struct io_region region;
struct block_device *bdev;
char *buf;
unsigned long flag, i;
bdev = open_bdev_excl(PATH, FMODE_READ, NULL);
if (IS_ERR(bdev)) {
printk(KERN_ALERT "open bdev failed./n");
goto out1;
}
buf = (char *)vmalloc(512);
if (!buf) {
printk(KERN_ALERT "alloc memory failed./n");
goto out2;
}
region.bdev = bdev;
region.sector = 0;
region.count = 1;
dm_io_sync_vm(1, ®ion, READ, buf, &flag);
for (i = 0; i < 512; i++) {
printk(KERN_ALERT "%c", buf[i]);
buf[i] = 'A';
}
printk(KERN_ALERT "/n");
dm_io_sync_vm(1, ®ion, WRITE, buf, &flag);
close_bdev_excl(bdev);
return 0;
out2:
close_bdev_excl(bdev);
out1:
return -1;
}
做法非常简单,只要有一个io_region结构,然后调用dm_io_sync_vm函数就可以了。其实这是一系列的函数,linux内核文档中有详细的解释,但是要注意几个问题
1. dm_io_sync_vm 所使用的内存空间(也就是buf参数)必须是用vmalloc函数分配的,如果是kmalloc分配的话,会出现panic。由此看来kmalloc和vmalloc的区别比我们知道的要大。具体有什么差距我也不知道。
2. 注意头文件的引用,这样引用的原因是dm_io这一套接口并不是所有的内核版本都会有的。有的内核版本根本没有包含这些接口,甚至有些虽然包含了接口但参数不同,所以最保险的办法是把这两个文件随代码一起发布。