4

I have created block device in kernel module. When some I/O happens I read/write all data from/to another existing device (let's say /dev/sdb).

It opens OK, but read/write operations return 14 error(EFAULT,Bad Address). After some research I found that I need map address to user space(probably buffer or filp variables), but copy_to_user function does not help. Also I looked to mmap() and remap_pfn_range() functions, but I can not get how to use them in my code, especially where to get correct vm_area_struct structure. All examples that I found, used char devices and file_operations structure, not block device.

Any hints? Thanks for help.

Here is my code for reading:

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);
4

1 回答 1

2

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

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

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

比将成员own_make_request更改bi_bdevbio结构到您重定向 I/O 和调用generic_make_request函数的设备的功能:

bio->bi_bdev = device_in_which_redirect;
generic_make_request(bio);

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

2)如果你想从内核模块读取或写入你自己的数据到现有的块设备,你应该使用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*,因此您可以将该指针解释为您想要的任何内容。

于 2013-07-08T12:59:24.097 回答