Linux块设备总结(九)向内核中增加通用磁盘操作

本文介绍如何通过add_disk函数将通用磁盘结构体struct gendisk注册到内核,涉及设备号分配、块设备注册等步骤。

前一章我们介绍了通用磁盘结构体struct gendisk的申请操作,本章我们将要介绍申请完通用块结构体之后怎么把通用块结构体增加到内核空间去,并且使内核认识到:哦…这就是我们的磁盘啊! 使用此操作之后我们便可以随心所欲的操作我们的磁盘了。

主要函数

把通用磁盘结构体struct gendisk增加到内核的操作十分简单就是一个函数:add_disk。先说明一下这个函数的大体功能:

add_disk函数说明:
		传入参数:
				@struct gendisk* disk    :   向内核添加入通用磁盘的结构体 
		返回值:
				void
		函数功能:
				向内核中完成通用磁盘的注册。
				主要完成一下操作:
						1. 获取MKDEV(disk->major, disk->part0.partno + disk->first_minor)头一个设备号的地址
						2. 向bdev_map散列表中注册进入块设备号的主设备号和次设备号。
						3. 使用BLKDEV文件系统第一次获取bdev结构,也就是把block_device注册进入bdev文件系统
						4. 把通用磁盘的工作队列的backing_dev_info注册进入系统

具体实现

add_disk代码全部实现如下:

void add_disk(struct gendisk *disk)
{
        struct backing_dev_info *bdi;
        dev_t devt;
        int retval;

        /* minors == 0 indicates to use ext devt from part0 and should
         * be accompanied with EXT_DEVT flag.  Make sure all
         * parameters make sense.
         */
        WARN_ON(disk->minors && !(disk->major || disk->first_minor));
        WARN_ON(!disk->minors && !(disk->flags & GENHD_FL_EXT_DEVT));

        disk->flags |= GENHD_FL_UP;

        retval = blk_alloc_devt(&disk->part0, &devt);
        if (retval) {
                WARN_ON(1);
                return;
        }
        disk_to_dev(disk)->devt = devt;

        /* ->major and ->first_minor aren't supposed to be
         * dereferenced from here on, but set them just in case.
         */
        disk->major = MAJOR(devt);
        disk->first_minor = MINOR(devt);

        blk_register_region(disk_devt(disk), disk->minors, NULL,
                            exact_match, exact_lock, disk);
        register_disk(disk);
        blk_register_queue(disk);

        bdi = &disk->queue->backing_dev_info;
        bdi_register_dev(bdi, disk_devt(disk));
        retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,
                                   "bdi");
        WARN_ON(retval);
}

代码解读:

  1. 获取MKDEV(disk->major, disk->part0.partno + disk->first_minor)头一个设备号的地址,以下代码就是实现此操作的目的,
        disk->flags |= GENHD_FL_UP;

        retval = blk_alloc_devt(&disk->part0, &devt);
        if (retval) {
                WARN_ON(1);
                return;
        }
        disk_to_dev(disk)->devt = devt;

其中blk_alloc_devt函数原型如下:

int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
{
        struct gendisk *disk = part_to_disk(part);
        int idx, rc;

        /* in consecutive minor range? */
        //此函的的主要部分,如果part->partno< disk->minors时候我们知道传入的part为part0,所以partno = 0, disk->minors则为大于零的数值。
        if (part->partno < disk->minors) {
                *devt = MKDEV(disk->major, disk->first_minor + part->partno);
                return 0;
        }       

        /* allocate ext devt */
        do {
                if (!idr_pre_get(&ext_devt_idr, GFP_KERNEL))
                        return -ENOMEM;
                rc = idr_get_new(&ext_devt_idr, part, &idx);
        } while (rc == -EAGAIN);

        if (rc)
                return rc;

        if (idx > MAX_EXT_DEVT) {
                idr_remove(&ext_devt_idr, idx);
                return -EBUSY;
        }
        
        *devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
        return 0;
}

上面函数最主要部分为: *devt = MKDEV(disk->major, disk->first_minor + part->partno);获取第一个设备号的值。
2. 向bdev_map散列表中注册进入块设备号的主设备号和次设备号。主要执行如下函数:

blk_register_region(disk_devt(disk), disk->minors, NULL,
                            exact_match, exact_lock, disk);

以上函数原型如下:

        blk_register_region(disk_devt(disk), disk->minors, NULL,
                           exact_match, exact_lock, disk);

其中bdev_map为kobj_map类型,其下的主要作用如下:
在这里插入图片描述3. 使用BLKDEV文件系统第一次获取bdev结构,也就是把block_device注册进入bdev文件系统
主要执行如下函数:

register_disk(disk);

此函数的主要作用如下:

1. 在/sys/目录下建立相应的目录,
2.向内核中增加part0.__dev设备。
3. 在/sys/block/xxx目录下建立holder slaves目录。
4. 在bdev目录下生成block_device结构并且测试、把bdev->invalite结构使能。
  1. 把通用磁盘的工作队列的backing_dev_info注册进入系统并且在/sys/block/xxxx目录下生成bdi目录。
内容概要:本文深入探讨了Linux块设备驱动的核心概念、框架结构及其开发实践。文章首先介绍了块设备驱动在Linux系统中的重要性,它作为操作系统与硬件设备间的桥梁,负责管理块设备的读写操作和缓存管理。接着对比了块设备驱动与字符设备驱动的区别,强调了前者在高效随机访问和大量数据处理方面的优势。随后,文章详细解析了块设备驱动的工作流程,从用户请求到硬件响应的全过程,涉及虚拟文件系统、映射层、通用块层、I/O调度层等关键环节。文中还剖析了核心数据结构如gendisk、block_device_operations、request_queue和request,并讲解了API的使用,包括注册与注销、磁盘设备操作等。最后,通过一个简单的块设备驱动实例,展示了从代码编写到测试验证的完整过程。; 适合人群:对Linux内核开发、设备驱动编程感兴趣的开发者,尤其是有一定C语言编程基础和技术背景的研发人员。; 使用场景及目标:①理解块设备驱动在Linux系统存储体系中的角色和工作原理;②掌握块设备驱动的核心数据结构和API的使用方法;③通过实战演练,能够编写、编译、加载和测试简单的块设备驱动程序。; 其他说明:随着存储技术和新兴技术的发展,块设备驱动面临新的挑战和机遇。开发者应关注新技术趋势,如SSD特性的优化、云计算和大数据环境下的高性能需求等,以不断提升块设备驱动的性能和可靠性。文章鼓励读者通过实际项目和实验积累经验,提升技术水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值