Module 从内核(3.7)模块读取块_设备:提交_bio中存在SEGFULT,缺少bd_磁盘

Module 从内核(3.7)模块读取块_设备:提交_bio中存在SEGFULT,缺少bd_磁盘,module,io,kernel,block-device,Module,Io,Kernel,Block Device,你好,斯塔克 想知道我在尝试直接从内核模块访问块设备时犯了什么错误。(amd64上的内核3.7) 我使用get_gendisk()获取设备的(struct gendisk*)。接下来,使用bio_map_kern()创建一个bio,使用bdget_disk()将block_设备添加到bio中,并使用submit_bio()发送它。(见下面的代码) 在“sdb”上执行此操作时,效果良好。在“loop0”或ramdisk设备上执行此操作时,会出现segfault故障。 故障可归结为泛型_make_r

你好,斯塔克

想知道我在尝试直接从内核模块访问块设备时犯了什么错误。(amd64上的内核3.7)

我使用get_gendisk()获取设备的(struct gendisk*)。接下来,使用bio_map_kern()创建一个bio,使用bdget_disk()将block_设备添加到bio中,并使用submit_bio()发送它。(见下面的代码)

在“sdb”上执行此操作时,效果良好。在“loop0”或ramdisk设备上执行此操作时,会出现segfault故障。 故障可归结为泛型_make_request_checks()调用内联函数bdev_get_queue(),该函数试图访问block_设备结构中的“bd_disk”字段

RIP:0010:[]一般性请求检查+0x3e/0x2b1

从“sdb”获取block_设备时,bd_磁盘将链接回设备的gendisk结构(在其任何分区上)。在“loop0”设备上尝试相同操作时,此指针为零。但是loop0设置正确,因为我可以使用它进行mkfs、mount或dd

有关于如何设置简单数据读取的提示吗?清洁和适当的方式?将gendisk指针添加到block_设备不是一个好的解决方案,因为我不“拥有”这些结构

也许这种方法完全错了,我错过了一个简单易读的()函数…:-)

调用堆栈(内核3.7,amd64):

[]通用请求检查+0x3e/0x2b1
[] ? 控制台锁定+0xf/0x47
[] ? vprintk_发射+0x3aa/0x3d0
[] ? 通用请求+0xe/0xd5
[] ? 提交_bio+0x10a/0x13b
[] ? 初始tryKM2+0x16e/0x221[tryKM2]
[] ? endFunc_tryKM2+0x23/0x23[tryKM2]
[] ? do_one_initcall+0x75/0x12b
[] ? 系统初始化模块+0x105/0x251
[] ? 系统调用快速路径+0x16/0x1b
我尝试此操作的测试代码:

#包括
#包括
#包括
#包括
#包括
#包括
#包括
类型定义结构\u drvDat
{
开发部;
结构gendisk*gd;
}drvDat;
#定义printf(…)printk(内核警报“tryKM2:”\uuuu VA\u ARGS\uuuuu)
#定义DEVNAME“loop0”
#定义分区号0
静态int init_tryKM2(无效)
{
int假人;
//初始自我
memset(&self,0,sizeof(self));
self.di=blk_lookup_devt(DEVNAME,0);//在这里使用分区零。gendisk句柄仍然相同。
if(self.di==0)
返回-1;
self.gd=get_gendisk(self.di,&dummy);//get_gendisk始终获取“磁盘”,即使dev_t指向分区。
if(self.gd==0)
返回-1;
//检查是否有分区(此数组始终至少有一个条目。这与&(self.gd->part0)相同)
if(self.gd->part\u tbl->lenbi\u private)
完成((结构完成*)(bb->bi_private));
}
静态void readbytes_tryKM2(drvDat*self)
{
结构生物*bb;
宣布完成(waithandle);
无符号字符*buf;
无符号整数i,j;
printf(“readbytes_tryKM2\n”);
buf=(无符号字符*)vmalloc(0x800);
memset(buf,0xFE,0x800);
bb=bio_-map_-kern(self->gd->queue,buf,0x400,GFP_-KERNEL);
如果(是错误(bb))
{vfree(buf);return;}
bb->bi_扇区=0;
bb->bi_bdev=bdget_磁盘(self->gd,分区号);
printf(“biu-bdev=%016lX\n”,(无符号长)(bb->biu-bdev));
printf(“biu-bdev->bd-u-disk=%016lX\n”,(无符号长)(bb->biu-bdev->bd-disk));
bb->bi_end_io=endFunc_tryKM2;
bb->bi_private=&waithandle;
printf(“发送…\n”);
提交_bio(0,bb);
printf(“等待…\n”);
等待完成(&waithandle);
printf(“done.flags=0x%X\n”,(unsigned int)(bb->bi_标志));

如果(!(bb->bi_flags&(1而不是bb->bi_bdev=bdget_disk(self->gd,PARTITIONNO));
试试这个bb->bi_bdev=blkdev_get_by_dev(self->di,FMODE_READ | FMODE_WRITE | FMODE_EXCL,NULL);

我发现我会首先按路径查找bdev:

struct block_device *bdev;
bdev = lookup_bdev("/dev/loop0");
然后打开它:

bb->bi_bdev = blkdev_get_by_dev(bdev->bd_dev, FMODE_READ|FMODE_WRITE, NULL);

没有FMODE_EXCL。但完成后,需要关闭设备:

blkdev_put(bb->bi_bdev, FMODE_READ|FMODE_WRITE);

我发现…你在哪里发现的?一个链接会很好。否则很好的形式;我无法检查正确性。我很抱歉,我应该指定。“我发现”来自个人在编写访问物理硬盘的块设备驱动程序时的经验。代表互联网:感谢分享你的经验。:-)
bb->bi_bdev = blkdev_get_by_path("/dev/loop0", FMODE_READ|FMODE_WRITE, NULL);
blkdev_put(bb->bi_bdev, FMODE_READ|FMODE_WRITE);