阅读从内核(3.7)模块block_device:段错误的submit_bio,bd_disk丢失(

2019-08-16 16:26发布

你好计算器。

想知道我得到了什么错试图直接从内核模块访问块设备。 (在AMD64内核3.7)

我得到的使用设备get_gendisk的(结构的gendisk *)()。 接下来,创建bio_map_kern(生物),使用bdget_disk()的block_device添加到它,并使用submit_bio发送()。 (见下面的代码)

当这样的“深发展”,它工作正常。 当这样做的“回路0”或一个ramdisk设备时,出现段错误。 故障归结为generic_make_request_checks()调用内联函数bdev_get_queue(),这是试图以访问block_device结构中的“bd_disk”字段。

RIP:0010:[] [] generic_make_request_checks + 0x3E的/ 0x2b1

当正从“深发展”的block_device,该bd_disk连接回设备的结构的gendisk(关于它的任何分区)。 当试图在“回路0”设备上一样,这个指针为零。 但回路0的设置是否正确,我可以MKFS,它安装或DD。

关于如何建立一个简单的数据任何提示看? 清洁和适当的方法是什么? 添加的gendisk指针block_device不能是一个很好的解决方案,我不知道“自己”的结构。

也许这种做法是完全错误的,并有我错过了一些简单的read()函数... :-)

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

[<ffffffff812796f5>] generic_make_request_checks+0x3e/0x2b1
[<ffffffff8103c2b8>] ? console_trylock+0xf/0x47
[<ffffffff8103dad0>] ? vprintk_emit+0x3aa/0x3d0
[<ffffffff81279976>] ? generic_make_request+0xe/0xd5
[<ffffffff8127a75c>] ? submit_bio+0x10a/0x13b
[<ffffffffa02ad191>] ? init_tryKM2+0x16e/0x221 [tryKM2]
[<ffffffffa02ad023>] ? endFunc_tryKM2+0x23/0x23 [tryKM2]
[<ffffffff810020b6>] ? do_one_initcall+0x75/0x12b
[<ffffffff8107c9a3>] ? sys_init_module+0x105/0x251
[<ffffffff8145f1e9>] ? system_call_fastpath+0x16/0x1b

对于尝试这种我的测试代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/genhd.h>
#include <linux/bio.h>
#include <linux/completion.h>

typedef struct _drvDat
{
    dev_t di;
    struct gendisk *gd;
} drvDat;

#define printf(...) printk(KERN_ALERT "tryKM2: " __VA_ARGS__)
#define DEVNAME "loop0"
#define PARTITIONNO 0

static int init_tryKM2(void)
{
  int dummy;
    // init self
    memset(&self,0,sizeof(self));

    self.di = blk_lookup_devt(DEVNAME,0);    // use partition zero here. gendisk handle is same anyway.
    if(self.di==0)
        return -1;
    self.gd = get_gendisk(self.di,&dummy);        // get_gendisk always gets the 'disk', even if dev_t points to a partition.
    if(self.gd==0)
        return -1;

    // check if have partitions  (this array always has at least one entry. That is same as &(self.gd->part0)
    if(self.gd->part_tbl->len<1+PARTITIONNO)
        {put_disk(self.gd);self.gd=0;return -1;}

    readbytes_tryKM2(&self);

    return 0;
}

static void endFunc_tryKM2(struct bio *bb, int err)
{
    if(bb->bi_private)
        complete( (struct completion*)(bb->bi_private) );
}

static void readbytes_tryKM2(drvDat *self)
{
  struct bio *bb;
  DECLARE_COMPLETION_ONSTACK(waithandle);
  unsigned char *buf;
  unsigned int i,j;

    printf("readbytes_tryKM2\n");
    buf = (unsigned char*)vmalloc(0x800);
    memset( buf , 0xFE , 0x800 );


    bb = bio_map_kern( self->gd->queue , buf , 0x400 , GFP_KERNEL );
    if( IS_ERR(bb) )
        {vfree(buf);return;}

    bb->bi_sector = 0;

    bb->bi_bdev = bdget_disk(self->gd,PARTITIONNO);
    printf("   bi_bdev = %016lX\n",(unsigned long)(bb->bi_bdev));
    printf("   bi_bdev->bd_disk = %016lX\n",(unsigned long)(bb->bi_bdev->bd_disk));

    bb->bi_end_io = endFunc_tryKM2;
    bb->bi_private = &waithandle;

    printf("  send...\n");
    submit_bio( 0 , bb );
    printf("  wait...\n");
    wait_for_completion(&waithandle);

    printf("  done. flags=0x%X\n",(unsigned int)(bb->bi_flags));

    if(!( bb->bi_flags & (1<<BIO_UPTODATE) ))
        {bio_put(bb);vfree(buf);return;}

    // just dump data... (misusing upper half of buffer)
    for(i=0;i<0x400;i+=0x20)
    {
        for(j=0;j<0x20;j++)
            snprintf( (char*)(buf+0x400+3*j) , 8 , "%02X " , (unsigned int)buf[i+j] );
        buf[3*0x20-1]=0;
        printf("   %s\n",buf+0x400);
    }

    bio_put(bb);

    vfree(buf);
}

module_init(init_tryKM2);
module_exit(cleanup_tryKM2);

Answer 1:

代替的BB-> bi_bdev = bdget_disk(自> GD,PARTITIONNO); 尝试这种BB-> bi_bdev = blkdev_get_by_dev(自>二,FMODE_READ | FMODE_WRITE | FMODE_EXCL,NULL);



Answer 2:

我发现,我会先通过其路径查找的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);

要么

bb->bi_bdev = blkdev_get_by_path("/dev/loop0", FMODE_READ|FMODE_WRITE, NULL);

没有FMODE_EXCL。 但是当你做,你需要关闭设备:

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


文章来源: Reading block_device from kernel (3.7) module: segfault in submit_bio, bd_disk is missing