第6章 设备驱动程序(4)

目录

6.5 块设备操作

6.5.5 请求结构

6.5.6 BIO

6.5.7 提交请求

6.5.8 I/O调度

6.5.9 ioctl实现


本专栏文章将有70篇左右,欢迎+关注,查看后续文章。

6.5 块设备操作

6.5.5 请求结构

struct         request {         //放在请求队列上,请求完成放到donelist链表上。

        struct request_queue         *q;

        struct list_head                  queuelist;            //用于挂载到请求队列中。

        struct gendisk                    *rq_disk;

        struct hd_struct                 *part;

        sector_t                             sector;                 //请求的起始扇区。

        unsigned long                   nr_sectors;          //请求包含的的扇区数。

        unsigned int                     current_nr_sectors;

        struct bio                         *bio;                         //表示底层的I/O 请求。

        struct bio                         *biotail;                   //一个请求可包含多个bio,指向最后一个bio。

        void                                 *elevator_private;         //IO调度器设置。

        void                                 *elevator_private2;

        unsigned short                         nr_phys_segments;        //请求涉及连续物理区域数。

        unsigned short                         nr_hw_segments;           //重排序的请求中连续物理区域数。

        enum rq_cmd_type_bits         cmd_type;                        //如:REQ_TYPE_FS。

        unsigned int                        cmd_flags;                          //如:_REQ_RW表示数据传输方向。

        unsigned int                        cmd_len;

}

BIO:用于内核和设备间传输数据。下节讲。

struct request在更高层次表示块设备的整体I/O请求,包含多个struct bio

6.5.6 BIO

bio:描述单个IO读写请求。

struct         bio {

        struct bio                         *bi_next;

        struct block_device         *bi_bdev;         // 对应块设备。

        sector_t                           bi_sector;        // 请求传输的开始扇区号。

        unsigned int                    bi_size;           // 请求数据的长度。

        unsigned short               bi_vcnt;           // bi_io_vec数组元素个数,即数据缓冲区数量。

        unsigned short              bi_idx;              // 作为数组bi_io_vec的索引。

        struct bio_vec               *bi_io_vec;

}

struct         bio_vec {

        struct page          *bv_page;         // 缓冲区所在页。

        unsigned int         bv_len;             // 缓冲区长度。

        unsigned int         bv_offset;         // 缓存区在页内的偏移。

};

6.5.7 提交请求

内核将IO请求提交给设备,步骤:

        1. 创建一个bio以描述请求 ,并嵌入到request中,放到request_queue中。

        2. 内核处理请求队列,并执行bio中的请求。

bio创建后,调用struct request_queue中make_request_fn函数指针,将新请求加入请求队列。

而request_fn用于提交请求。

1. 创建IO请求

submit_bio:

        根据bio创建一个新request。

        使用make_request_fn将request加入到request_queue中。

2. 队列插入

为提高IO性能,尽可能重排或合并各个请求。

队列空闲时:处理队列中请求。否则只添加请求到队列,而不处理。

请求插入队列后,后续何时处理请求?

       1. 定时器。
        2. 请求超过阈值。

3. 执行请求

执行请求:

        struct request_queue->request_fn()函数指针。

struct request_queue    *blk_init_queue(request_fn_proc     *rfn,     spinlock_t     *lock)

        用于设置request_fn()函数指针。

        不同设备驱动中调用该函数设为不同函数。

6.5.8 I/O调度

I/O调度器:也叫电梯。

        用于调度和重排磁盘IO读写操作请求。以优化磁盘访问的顺序和效率。

一个调度器包含的操作:

struct elevator_ops {

        elevator_merge_fn                 *elevator_merge_fn;

                //检查新请求是否可以和现有请求合并。

        elevator_merged_fn                 *elevator_merged_fn;

                //合并后调用。

        elevator_merge_req_fn         *elevator_merge_req_fn;

                //执行请求合并。

        elevator_allow_merge_fn         *elevator_allow_merge_fn;

                //是否可以将当前请求与现有请求合并。

        elevator_bio_merged_fn         *elevator_bio_merged_fn;

                //当一个bio被合并到一个请求中时调用。

        elevator_dispatch_fn                 *elevator_dispatch_fn;

                //从指定队列中选择下一个调度的请求给设备驱动。

        elevator_add_req_fn                 *elevator_add_req_fn;

                //向队列添加请求。

        elevator_activate_req_fn                 *elevator_activate_req_fn;

        elevator_deactivate_req_fn             *elevator_deactivate_req_fn;

                //当请求变为活动/非活动时调用。

        elevator_completed_req_fn         *elevator_completed_req_fn;

                //当一个请求完成时调用。

        elevator_init_icq_fn                 *elevator_init_icq_fn;

        elevator_exit_icq_fn                 *elevator_exit_icq_fn;

                //初始化/清理 I/O上下文队列。

        elevator_set_req_fn                 *elevator_set_req_fn;

        elevator_put_req_fn                 *elevator_put_req_fn;

        elevator_may_queue_fn         *elevator_may_queue_fn;

                //是否可将请求添加到请求队列。

        elevator_init_fn                 *elevator_init_fn;

        elevator_exit_fn                 *elevator_exit_fn;

                //调度器初始化时、退出时调用。

}

请求上下文(I/O Context Queue, ICQ):

        ICQ 存储与请求相关上下文,如文件系统元数据、锁状态等。

表示一个调度器:

struct         elevator_type

{

        struct kmem_cache         *icq_cache;

        struct elevator_ops         ops;

        size_t                             icq_size;

        size_t                             icq_align;

        struct elv_fs_entry         *elevator_attrs;         //sysfs中的属性。

        char                                 elevator_name[ELV_NAME_MAX];         //调度器名称。

        struct module                 *elevator_owner;

        struct list_head                 list;         //连接所有IO调度器。

};

内核的IO调度器有:

        1. elevator_noop:

                简单,先来先服务。可合并请求,但不能重排。

                使用场景:

                        1. 可自行重排的智能硬件。

                        2. 不用寻道的设备, 如闪存。

        2. iosched_deadline:

                目的:

                        最小化寻道次数。

                        尽可能在一定时间内完成。

        3. iosched_cfq:

                完全公平队列。默认调度器。

                每个进程有一个队列,轮询调度多个队列。

拓展

常见I/O调度算法:

        完全公平队列(CFQ):

                为每个进程提供公平访问磁盘机会。将磁盘带宽分配给不同进程。

                适用于多任务公平共享磁盘资源环境。

        Deadline:

                适用于低延迟应用,如实时应用,数据库。

        Noop:

                不重排序不优化。

                适用不需要额外调度开销的情况,如SSD设备。

        电梯算法:

                优化了磁盘访问顺序,减少寻道时间。

                模拟电梯上下移动,根据磁头当前位置和移动方向,调度最近请求 。

                对于磁盘访问密集型且随机的I/O,显著提高性能。

                缺点:

                        当磁头频繁改变方向时,一些请求可能长时间等待。

                        因此需要根据实际应用的特点和需求权衡。

6.5.9 ioctl实现

系统调用 - > sys_ioctl -> vfs_ioctl

blkdef_ioctl:实现了某些ioctl,对于所有块设备都可用。

        如:读取设备分区信息,设备总长度。

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
I/O设备管理是操作系统中的一个重要组成部分,它负责管理计算机系统中的各种输入输出设备,包括硬盘、键盘、鼠标、打印机等。在本的下半部分,我们将继续深入讨论I/O设备管理的相关内容。 1. I/O设备驱动程序 I/O设备驱动程序是操作系统中的一个重要组成部分,它负责将操作系统和I/O设备之间进行交互。通常来说,每一种I/O设备都需要对应一个相应的驱动程序。I/O设备驱动程序通常由操作系统厂商提供,也可以由第三方厂商提供。 2. 中断处理程序 当一个I/O设备完成了一个输入输出操作时,它会向CPU发送一个中断请求,以通知CPU有一个I/O设备需要处理。CPU在接收到中断请求后,会暂停当前正在执行的任务,并执行中断处理程序。中断处理程序是操作系统中的一个重要组成部分,它负责处理中断请求,并将结果返回给I/O设备驱动程序。 3. 缓存管理 缓存是操作系统中的一个重要概念,它指的是在内存中存储的数据副本。I/O设备管理中的缓存可以分为两种,一种是输入缓存,用于存储从I/O设备读取的数据;另一种是输出缓存,用于存储将要写入I/O设备的数据。缓存管理的目的是提高I/O设备的读写效率,减少CPU对I/O设备的访问次数。 4. 设备控制块 设备控制块是操作系统中的一个数据结构,用于管理I/O设备。每一个I/O设备都有一个相应的设备控制块,它包含了I/O设备的基本信息,包括设备类型、设备状态、缓存信息等。设备控制块还可以用于实现多任务操作,即同时处理多个I/O设备请求。 5. 通道控制程序 通道控制程序是操作系统中的一个重要组成部分,它负责管理计算机系统中的通道设备。通道设备是一种高速输入输出设备,通常用于处理大量数据的输入输出操作。通道控制程序可以将多个I/O设备的请求合并,以提高系统的输入输出效率。 总之,I/O设备管理是操作系统中的一个重要组成部分,它涉及到多个方面的内容,包括I/O设备驱动程序、中断处理程序、缓存管理、设备控制块和通道控制程序等。在实际应用中,需要根据具体的需求和系统架构,选择合适的I/O设备管理策略,以提高系统的性能和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山下小童

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值