内核块设备
Kernel block device
我目前正在尝试实现一个(不是那个?)简单的内核块设备 driver。
我的灵感主要来自 Linux Device Drivers, 3rd Edition 这本书,这本书已不再是 up-to-date,因为它于 2005 年出版。
反正逻辑还在,学到了很多东西。然而,示例并不是真正有效,因为自 2005 年以来很多事情都发生了变化。
我找到了一个 github repository,其中的示例应该更新以在最近的内核上运行,但我认为仍有一些东西需要更新,因为我无法调整示例以使其在 上运行内核 4.9.0
我的模块是这样制作的:
初始化时:
- 使用
register_blkdev
将模块注册为块设备
- 分配设备数据缓冲区
- 初始化自旋锁
- 初始化请求queue
- 配置请求queue
- 分配
gendisk
结构
- 填写
gendisk
结构
- 使用
add_disk
创建磁盘
然后我实现了一个函数来处理来自requestqueue的request事件和处理块设备上的读写事件
这是函数:(它的灵感来自 LLD-3rd,并进行了一些修改以匹配当前的内核函数)
static void block_mod_request(struct request_queue *queue)
{
printk(KERN_NOTICE "Entering request function\n");
struct request *request;
while(NULL != (request = blk_fetch_request(queue)))
{
blk_mod_t *self = request->rq_disk->private_data;
// Check if request is a filesystem request (i.e. moves block of data)
if(REQ_TYPE_FS != request->cmd_type)
{
// Close request with unsuccessful status
printk(KERN_WARNING "Skip non-fs request\n");
__blk_end_request_cur(request, -EIO);
continue;
}
// Treat request
block_mod_transfer(self, blk_rq_pos(request), blk_rq_cur_sectors(request), request->buffer, rq_data_dir(request));
// Close request with successful status
__blk_end_request_cur(request, 0);
}
return;
}
但是在编译时出现了以下错误:
block_mod.c:82:91: error: ‘struct request’ has no member named ‘buffer’
block_mod_transfer(self, blk_rq_pos(request), blk_rq_cur_sectors(request), request->buffer, rq_data_dir(request));
将文件 blkdev.h
检查到内核 v4.9.0 headers 后,字段 buffer
似乎不再存在于 struct request
.
但是,我无法找到任何关于事物如何演变以及如何修改代码以使其工作的信息。
如果我理解得很好,buffer
字段应该是指向虚拟内核地址的指针。我想一旦这个缓冲区 filled/read 内核处理数据传输 to/from 用户空间。
我有点迷路了,因为如果请求不再提供内核虚拟地址,我找不到应该在哪里找到它。
我怎么知道在哪里传输数据?
包含罪魁祸首的提交消息,由 Ming Lei 撰写:
block: remove struct request buffer member
This was used in the olden days, back when onions were proper
yellow. Basically it mapped to the current buffer to be
transferred. With highmem being added more than a decade ago,
most drivers map pages out of a bio, and rq->buffer
isn't
pointing at anything valid.
Convert old style drivers to just use bio_data()
.
有一些很好的阅读 BIO 的资源,例如 lwn 上的 this post。相关片段:
char *bio_data(struct bio *bio)
Returns the kernel virtual address for the data buffer.
所以看起来使用 bio_data(rq->bio)
代替 rq->buffer
会更成功。
作者编辑:
还发现 this link 它分为两部分,第一部分是生物层,第二部分是请求层。
我目前正在尝试实现一个(不是那个?)简单的内核块设备 driver。
我的灵感主要来自 Linux Device Drivers, 3rd Edition 这本书,这本书已不再是 up-to-date,因为它于 2005 年出版。
反正逻辑还在,学到了很多东西。然而,示例并不是真正有效,因为自 2005 年以来很多事情都发生了变化。
我找到了一个 github repository,其中的示例应该更新以在最近的内核上运行,但我认为仍有一些东西需要更新,因为我无法调整示例以使其在 上运行内核 4.9.0
我的模块是这样制作的:
初始化时:
- 使用
register_blkdev
将模块注册为块设备
- 分配设备数据缓冲区
- 初始化自旋锁
- 初始化请求queue
- 配置请求queue
- 分配
gendisk
结构 - 填写
gendisk
结构 - 使用
add_disk
创建磁盘
然后我实现了一个函数来处理来自requestqueue的request事件和处理块设备上的读写事件
这是函数:(它的灵感来自 LLD-3rd,并进行了一些修改以匹配当前的内核函数)
static void block_mod_request(struct request_queue *queue)
{
printk(KERN_NOTICE "Entering request function\n");
struct request *request;
while(NULL != (request = blk_fetch_request(queue)))
{
blk_mod_t *self = request->rq_disk->private_data;
// Check if request is a filesystem request (i.e. moves block of data)
if(REQ_TYPE_FS != request->cmd_type)
{
// Close request with unsuccessful status
printk(KERN_WARNING "Skip non-fs request\n");
__blk_end_request_cur(request, -EIO);
continue;
}
// Treat request
block_mod_transfer(self, blk_rq_pos(request), blk_rq_cur_sectors(request), request->buffer, rq_data_dir(request));
// Close request with successful status
__blk_end_request_cur(request, 0);
}
return;
}
但是在编译时出现了以下错误:
block_mod.c:82:91: error: ‘struct request’ has no member named ‘buffer’
block_mod_transfer(self, blk_rq_pos(request), blk_rq_cur_sectors(request), request->buffer, rq_data_dir(request));
将文件 blkdev.h
检查到内核 v4.9.0 headers 后,字段 buffer
似乎不再存在于 struct request
.
但是,我无法找到任何关于事物如何演变以及如何修改代码以使其工作的信息。
如果我理解得很好,buffer
字段应该是指向虚拟内核地址的指针。我想一旦这个缓冲区 filled/read 内核处理数据传输 to/from 用户空间。
我有点迷路了,因为如果请求不再提供内核虚拟地址,我找不到应该在哪里找到它。
我怎么知道在哪里传输数据?
包含罪魁祸首的提交消息,由 Ming Lei 撰写:
block: remove struct request buffer member
This was used in the olden days, back when onions were proper yellow. Basically it mapped to the current buffer to be transferred. With highmem being added more than a decade ago, most drivers map pages out of a bio, and
rq->buffer
isn't pointing at anything valid.Convert old style drivers to just use
bio_data()
.
有一些很好的阅读 BIO 的资源,例如 lwn 上的 this post。相关片段:
char *bio_data(struct bio *bio)
Returns the kernel virtual address for the data buffer.
所以看起来使用 bio_data(rq->bio)
代替 rq->buffer
会更成功。
作者编辑:
还发现 this link 它分为两部分,第一部分是生物层,第二部分是请求层。