最近在编写块设备驱动,使用制造请求队列函数时,set_bit()和bio_endio()函数报错,请问这是什么原因?

最近在编写块设备驱动,使用制造请求队列函数时,set_bit()和bio_endio()函数报错,请问这是什么原因?

set_bit(BIO_UPTODATE, &bio->bi_flags);
    bio_endio(bio, 0);

总体代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/*参考例程*/

/*定义磁盘大小,内存模式*/
#define RAMDISK_SIZE        (2  *   1024    *   1024)   /*大小2MB*/
#define RAMDISK_NAME    "ramdisk"                 /*名字*/
#define RAMDISK_MINOR   3                                   /*表示3个分区*/


/*ramdisk设备结构体*/
struct ramdisk_dev
{
    int major;              /*主设备号*/
    unsigned    char    *ramdiskbuf;        /*ramdisk的内存空间,模拟磁盘的空间*/
    struct  gendisk *gendisk;
    struct  request_queue   *queue;
    spinlock_t  lock;       /*自旋锁*/
};

struct  ramdisk_dev ramdisk;
#if 0
/*具体的数据处理过程*/
static  void    ramdisk_transfer(struct request *req)
{
    /*数据传输三要素:源,目的,长度。
    *内存地址,块设备地址,长度
    */
   unsigned long    start   =   blk_rq_pos(req) <<  9;      /*blk_rq_pos获取到要操作的块设备扇区地址,左移9位,地址字节*/
   unsigned long    len =   blk_rq_cur_bytes(req);          /*数据长度*/

    /*获取bio里面的缓冲区:
    *如果是读:从磁盘里面读取到的数据保存在缓冲区里面
    *如果是写:此缓冲区保存着要写入到磁盘里面的数据
    */
   void *buffer =   bio_data(req->bio);

    if(rq_data_dir(req) ==   READ)               /*读操作*/
        memcpy(buffer,  ramdisk.ramdiskbuf  +   start,  len);
    else                                                                    /*写操作*/
        memcpy(ramdisk.ramdiskbuf  +   start,  buffer, len);

}
#endif
/*制造请求函数*/
static  void    ramdisk_make_request(struct request_queue   *queue, struct  bio *bio)
{
    int offset;
    struct  bio_vec bvec;
    struct  bvec_iter   iter;
    unsigned    long    len =   0;

    offset  =   bio->bi_iter.bi_sector   <<  9;      /*要操作的磁盘起始扇区偏移,改为字节地址*/

    /*循环处理每个段*/
    bio_for_each_segment(bvec,  bio,    iter)   {
    /*获取bio里面的缓冲区:
    *如果是读:从磁盘里面读取到的数据保存在缓冲区里面
    *如果是写:此缓冲区保存着要写入到磁盘里面的数据
    */
        char    *ptr    =   page_address(bvec.bv_page)  +   bvec.bv_offset;
        len =   bvec.bv_len;        /*长度*/

        if(bio_data_dir(bio) ==   READ)               /*读操作*/
            memcpy(ptr,  ramdisk.ramdiskbuf  +   offset,  len);
        else                                                                    /*写操作*/
            memcpy(ramdisk.ramdiskbuf  +   offset,  ptr, len);

        offset  +=  len;
    }

    set_bit(BIO_UPTODATE,   &bio->bi_flags);
    bio_endio(bio,  0);
}


static  int ramdisk_open(struct block_device    *bdev,  fmode_t mode)
{
    printk("ramdisk_open\r\n");
    return  0;
}

static  void    ramdisk_release(struct  gendisk *disk,  fmode_t mode)
{
    printk("ramdisk_release\r\n");
}

static  int    ramdisk_getgeo(struct   block_device   *dev,  struct  hd_geometry    *geo)
{
    printk("ramdisk_getgeo\r\n");
    /*硬盘信息*/
    geo->heads  =   2;      /*磁头*/
    geo->cylinders  =   32;         /*柱面,磁道*/
    geo->sectors    =   RAMDISK_SIZE/(2  *   32  *   512);   /*一个磁道里面的扇区数量*/
    
    return  0;
}

/*块设备操作集*/
static  const   struct  block_device_operations ramdisk_fops    =   
{
    .owner          =   THIS_MODULE,
    .open             = ramdisk_open,
    .release        =   ramdisk_release,
    .getgeo         =   ramdisk_getgeo,
};

/* 驱动入口函数 */
static int __init ramdisk_init(void)
{
    int ret =   0;
    printk("ramdisk_init\r\n");

    /*1.先申请内存*/
    ramdisk.ramdiskbuf  =   kzalloc(RAMDISK_SIZE,   GFP_KERNEL);
    if(ramdisk.ramdiskbuf   ==  NULL){
            ret =   -EINVAL;
            goto    ramalloc_fail;
    }
    /*2.注册块设备*/
    ramdisk.major   =   register_blkdev(0,RAMDISK_NAME);
    if(ramdisk.major    <   0)  {
        ret =   -EINVAL;
        goto    ramdisk_register_blkdev_fail;
    }
    printk("ramdisk major   =   %d\r\n",    ramdisk.major);

    /*3.申请gendisk*/
    ramdisk.gendisk =   alloc_disk(RAMDISK_MINOR);
    if(!ramdisk.gendisk){
        ret =   -EINVAL;
        goto    gendisk_alloc_fail;
    }

/*4.初始化自旋锁*/
spin_lock_init(&ramdisk.lock);

/*5.申请请求队列*/
ramdisk.queue   =   blk_alloc_queue(GFP_KERNEL);
if(!ramdisk.queue){
    ret =   -EINVAL;
    goto    blk_queue_fail;
}

/*绑定"制造请求"函数*/
blk_queue_make_request(ramdisk.queue,   ramdisk_make_request);

/*6.初始化gendisk*/
ramdisk.gendisk->major  =   ramdisk.major;      /*主设备号*/
ramdisk.gendisk->first_minor    =   0;
ramdisk.gendisk->fops   =   &ramdisk_fops;
ramdisk.gendisk->private_data   =   &ramdisk;
ramdisk.gendisk->queue  =   ramdisk.queue;
sprintf(ramdisk.gendisk->disk_name, RAMDISK_NAME);
set_capacity(ramdisk.gendisk,  RAMDISK_SIZE/512);      /*设置gendisk容量,单位扇区*/

add_disk(ramdisk.gendisk);

return  0;

blk_queue_fail:
    put_disk(ramdisk.gendisk);
gendisk_alloc_fail:
    unregister_blkdev(ramdisk.major,    RAMDISK_NAME);
ramdisk_register_blkdev_fail:
    kfree(ramdisk.ramdiskbuf);
ramalloc_fail:
    return ret;
}

/* 驱动出口函数 */
static void __exit ramdisk_exit(void)
{
    printk("ramdisk     exit\r\n");
    del_gendisk(ramdisk.gendisk);
    put_disk(ramdisk.gendisk);

    blk_cleanup_queue(ramdisk.queue);

    unregister_blkdev(ramdisk.major,    RAMDISK_NAME);
    kfree(ramdisk.ramdiskbuf);
}

module_init(ramdisk_init);
module_exit(ramdisk_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ty");

具体报错如下:

make -C /home/user/linux/rv/kernel M=/home/user/linux/study/ramdisk_makerequest ARCH=arm CROSS_COMPILE=/home/user/linux/rv/prebuilts/gcc/linux-x86/arm/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/arm-linux-gnueabihf- modules 
make[1]: 进入目录“/home/user/linux/rv/kernel”
  CC [M]  /home/user/linux/study/ramdisk_makerequest/ramdisk.o
In file included from ./include/linux/bitops.h:19,
                 from ./include/linux/kernel.h:11,
                 from ./include/linux/list.h:9,
                 from ./include/linux/module.h:9,
                 from /home/user/linux/study/ramdisk_makerequest/ramdisk.c:1:
/home/user/linux/study/ramdisk_makerequest/ramdisk.c: In function 'ramdisk_make_request':
/home/user/linux/study/ramdisk_makerequest/ramdisk.c:98:13: error: 'BIO_UPTODATE' undeclared (first use in this function); did you mean 'IS_PRIVATE'?
     set_bit(BIO_UPTODATE,   &bio->bi_flags);
             ^~~~~~~~~~~~
./arch/arm/include/asm/bitops.h:183:42: note: in definition of macro 'ATOMIC_BITOP'
 #define ATOMIC_BITOP(name,nr,p)  _##name(nr,p)
                                          ^~
/home/user/linux/study/ramdisk_makerequest/ramdisk.c:98:5: note: in expansion of macro 'set_bit'
     set_bit(BIO_UPTODATE,   &bio->bi_flags);
     ^~~~~~~
/home/user/linux/study/ramdisk_makerequest/ramdisk.c:98:13: note: each undeclared identifier is reported only once for each function it appears in
     set_bit(BIO_UPTODATE,   &bio->bi_flags);
             ^~~~~~~~~~~~
./arch/arm/include/asm/bitops.h:183:42: note: in definition of macro 'ATOMIC_BITOP'
 #define ATOMIC_BITOP(name,nr,p)  _##name(nr,p)
                                          ^~
/home/user/linux/study/ramdisk_makerequest/ramdisk.c:98:5: note: in expansion of macro 'set_bit'
     set_bit(BIO_UPTODATE,   &bio->bi_flags);
     ^~~~~~~
/home/user/linux/study/ramdisk_makerequest/ramdisk.c:98:29: error: passing argument 2 of '_set_bit' from incompatible pointer type [-Werror=incompatible-pointer-types]
     set_bit(BIO_UPTODATE,   &bio->bi_flags);
                             ^~~~~~~~~~~~~~
./arch/arm/include/asm/bitops.h:183:45: note: in definition of macro 'ATOMIC_BITOP'
 #define ATOMIC_BITOP(name,nr,p)  _##name(nr,p)
                                             ^
/home/user/linux/study/ramdisk_makerequest/ramdisk.c:98:5: note: in expansion of macro 'set_bit'
     set_bit(BIO_UPTODATE,   &bio->bi_flags);
     ^~~~~~~
./arch/arm/include/asm/bitops.h:153:55: note: expected 'volatile long unsigned int *' but argument is of type 'short unsigned int *'
 extern void _set_bit(int nr, volatile unsigned long * p);
                              ~~~~~~~~~~~~~~~~~~~~~~~~~^
/home/user/linux/study/ramdisk_makerequest/ramdisk.c:99:5: error: too many arguments to function 'bio_endio'
     bio_endio(bio,  0);
     ^~~~~~~~~
In file included from ./include/linux/blkdev.h:21,
                 from /home/user/linux/study/ramdisk_makerequest/ramdisk.c:26:
./include/linux/bio.h:448:13: note: declared here
 extern void bio_endio(struct bio *);
             ^~~~~~~~~
/home/user/linux/study/ramdisk_makerequest/ramdisk.c: In function 'ramdisk_init':
/home/user/linux/study/ramdisk_makerequest/ramdisk.c:172:41: error: passing argument 2 of 'blk_queue_make_request' from incompatible pointer type [-Werror=incompatible-pointer-types]
 blk_queue_make_request(ramdisk.queue,   ramdisk_make_request);
                                         ^~~~~~~~~~~~~~~~~~~~
In file included from /home/user/linux/study/ramdisk_makerequest/ramdisk.c:26:
./include/linux/blkdev.h:1206:60: note: expected 'blk_qc_t (*)(struct request_queue *, struct bio *)' {aka 'unsigned int (*)(struct request_queue *, struct bio *)'} but argument is of type 'void (*)(struct request_queue *, struct bio *)'
 extern void blk_queue_make_request(struct request_queue *, make_request_fn *);
                                                            ^~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
scripts/Makefile.build:339: recipe for target '/home/user/linux/study/ramdisk_makerequest/ramdisk.o' failed
make[2]: *** [/home/user/linux/study/ramdisk_makerequest/ramdisk.o] Error 1
Makefile:1641: recipe for target '_module_/home/user/linux/study/ramdisk_makerequest' failed
make[1]: *** [_module_/home/user/linux/study/ramdisk_makerequest] Error 2
make[1]: 离开目录“/home/user/linux/rv/kernel”
Makefile:12: recipe for target 'all' failed
make: *** [all] Error 2

“Devil组”引证GPT后的撰写:

  • et_bit()和bio_endio()函数报错可能是由于缺少头文件或函数定义不正确引起的。这两个函数都是属于Linux内核中的函数,set_bit()用于设置某个二进制位为1,bio_endio()用于结束块I/O操作。因此,需要在代码中包含正确的头文件并确保函数调用的正确性。
  • 在代码中,缺少的头文件是<linux/bitmap.h>,它包含set_bit()函数的定义。需要添加该头文件,以便编译器正确解析set_bit()函数。您可以在代码中添加以下行:
#include <linux/bitmap.h>

  • 在bio_endio()函数的情况下,它需要两个参数:第一个是指向结束I/O操作的struct bio结构的指针,第二个是表示I/O操作的错误代码。因此,要确保传递正确的参数。在代码中,第二个参数应该是0,表示I/O操作成功完成。如果I/O操作发生错误,应该传递相应的错误代码。以下是正确的bio_endio()函数调用示例:

bio_endio(bio, 0);

请注意,还需要在代码中定义ramdisk_make_request()函数,该函数将用于处理I/O请求。在您的代码中,该函数似乎已经定义,但是被注释掉了。因此,要取消注释该函数,并确保它与其他函数一起正确工作。

最后,为了更好地了解错误的原因,请在编译时启用调试信息,以便编译器可以输出更详细的错误信息。用以下命令进行编译:

  • make CONFIG_DEBUG_INFO=y

这可能是因为你在代码中没有包含正确的头文件,从而导致编译器无法识别set_bit()和bio_endio()函数。这两个函数的声明位于linux/bitmap.h和linux/blkdev.h头文件中。因此,为了解决这个问题,你需要在代码中添加以下两个头文件:

#include <linux/bitmap.h>
#include <linux/blkdev.h>