gpt4 book ai didi

linux-kernel - 从内核模块到设备的 I/O 失败并显示 EFAULT

转载 作者:行者123 更新时间:2023-12-02 02:00:46 26 4
gpt4 key购买 nike

我在内核模块中创建了 block 设备。当一些 I/O 发生时,我从另一个现有设备读取/写入所有数据(比如说 /dev/sdb )。

它打开正常,但读/写操作返回 14 错误(EFAULT,错误地址)。经过一番研究,我发现我需要将地址映射到用户空间(可能是 bufferfilp 变量),但是 copy_to_user功能没有帮助。我也看了mmap()remap_pfn_range()函数,但我不知道如何在我的代码中使用它们,尤其是在哪里得到正确的 vm_area_struct结构体。我发现的所有示例都使用了字符设备和 file_operations结构,而不是 block 设备。

有什么提示吗?感谢帮助。

这是我的阅读代码:

mm_segment_t old_fs;
old_fs = get_fs();
set_fs(KERNEL_DS);
filp = filp_open("/dev/sdb", O_RDONLY | O_DIRECT | O_SYNC, 00644);
if(IS_ERR(filp))
{
set_fs(old_fs);
int err = PTR_ERR(filp);
printk(KERN_ALERT"Can not open file - %d", err);
return;
}
else
{
bytesRead = vfs_read(filp, buffer, nbytes, &offset); //It gives 14 error
filp_close(filp, NULL);
}
set_fs(old_fs);

最佳答案

我找到了一种更好的 I/O 方法来阻止内核模块中的设备。我用过bio结构。希望这些信息可以使某人免于头痛。

1) 所以,如果你想将 I/O 从你的 block 设备重定向到现有的 block 设备,你必须使用自己的 make_request功能。为此,您应该使用 blk_alloc_queue为您的 block 设备创建队列的函数,如下所示:

device->queue = blk_alloc_queue(GFP_KERNEL);
blk_queue_make_request(device->queue, own_make_request);

比成 own_make_request功能变更 bi_bdev成员(member)加入 bio结构到您重定向 I/O 并调用 generic_make_request 的设备功能:
bio->bi_bdev = device_in_which_redirect;
generic_make_request(bio);

更多信息 here在第 16 章。如果链接由于某种原因被破坏,这里是书名 - “Linux 设备驱动程序,第三版”

2) 如果你想从内核模块读取或写入你自己的数据到现有的 block 设备,你应该使用 submit_bio功能。

写入特定扇区的代码(还需要实现 writeComplete功能):
void writePage(struct block_device *device,
sector_t sector, int size, struct page *page)
{
struct bio *bio = bio_alloc(GFP_NOIO, 1);
bio->bi_bdev = vnode->blkDevice;
bio->bi_sector = sector;
bio_add_page(bio, page, size, 0);
bio->bi_end_io = writeComplete;
submit_bio(WRITE_FLUSH_FUA, bio);
}

特定扇区读取代码(还需要实现 readComplete函数):
int readPage(struct block_device *device, sector_t sector, int size,
struct page *page)
{
int ret;
struct completion event;
struct bio *bio = bio_alloc(GFP_NOIO, 1);
bio->bi_bdev = device;
bio->bi_sector = sector;
bio_add_page(bio, page, size, 0);
init_completion(&event);
bio->bi_private = &event;
bio->bi_end_io = readComplete;
submit_bio(READ | REQ_SYNC, bio);
wait_for_completion(&event);
ret = test_bit(BIO_UPTODATE, &bio->bi_flags);
bio_put(bio);
return ret;
}
page可以用 alloc_page(GFP_KERNEL) 分配。也用于更改 page 中的数据使用 page_address(page) .它返回 void*因此您可以将该指针解释为您想要的任何内容。

关于linux-kernel - 从内核模块到设备的 I/O 失败并显示 EFAULT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17345760/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com