使用rmmod(del_gendisk)卸载时,Linux块设备模块已挂起

时间:2019-06-15 13:59:43

标签: c linux linux-kernel linux-device-driver

我正在为Linux中的块设备驱动程序写一个小例子。这个例子还不完整,我会逐步进行。我向blkdev_register注册了块设备,并向alloc_disk分配了gendisk结构。插入模块时,一切正常。它显示在 / proc / devices 中。但是,如果我想用rmmod卸载它,它将挂起。

我发现,在模块卸载功能中,对del_gendisk的调用导致挂起。我知道gendisk结构有一个嵌入式的kobject,它负责引用计数。这种机制阻止您在使用模块时卸载模块。但是由于我不叫add_disk,因此不应引用该结构。

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>

#define BLKDEVNAME  "blkdev_test"
#define MINORS      16  

struct block_device_operations bdops = {
    .owner = THIS_MODULE
};

struct blkdev {
    int major;  
    struct gendisk *disk;
    struct request_queue *queue;
} dev;


static int __init blkdev_init(void)         
{                                                                   
    dev.major = register_blkdev( 0, BLKDEVNAME );   
    if( dev.major < 0 )
        return -EIO;

    dev.disk = alloc_disk(MINORS);
    if( dev.disk == NULL )
        goto DISK_ERR;

    dev.disk->major = dev.major;
    dev.disk->first_minor = 0;
    snprintf(dev.disk->disk_name, DISK_NAME_LEN, "bd0" ); 
    dev.disk->fops = &bdops;
    // dev.disk->queue = dev.queue;

    // add_disk( dev.disk );

    return 0;

DISK_ERR:
    unregister_blkdev( dev.major, BLKDEVNAME ); 
    return -EIO;
}

static void __exit blkdev_exit(void) 
{
    del_gendisk(dev.disk);  
    unregister_blkdev( dev.major, BLKDEVNAME );
}

module_init(blkdev_init);   
module_exit(blkdev_exit);
MODULE_LICENSE("GPL");

如果我发出命令sudo rmmod mod.ko,那么该命令将被系统杀死。

1 个答案:

答案 0 :(得分:0)

Quoting

  

操作gendisk设置了gendisk结构后,您将   必须将其添加到活动磁盘列表中;通过以下方式完成:

void add_disk(struct gendisk *disk);
     

此呼叫后,您的设备处于活动状态。有几件事值得   注意add_disk():

add_disk() can create I/O to the device (to read partition tables and such). You should not call add_disk() until your driver is
sufficiently initialized to handle requests.

If you are calling add_disk() in your driver initialization routine, you should not fail the initialization process after the
first call.

The call to add_disk() increments the disk's reference count; if the disk structure is ever to be released, the driver is responsible
for decrementing that count (with put_disk()). 
     

是否需要从系统中删除磁盘,已完成   与:

void del_gendisk(struct gendisk *disk);
     

此功能清除与以下内容相关的所有信息:   给定的磁盘,通常将其从系统中删除。致电后   del_gendisk(),不会再有其他操作发送到给定的设备。   但是,驱动程序对gendisk对象的引用仍然存在。您   必须通过以下方式明确释放它:

void put_disk(struct gendisk *disk);
     

该调用将导致释放gendisk结构,只要没有   内核的其他部分保留对它的引用。