[Linux Driver]-Linux Device Driver-Related Structures of Block Device (2)

The relevant data structure was introduced at the end of last time, and I will introduce it in detail below

Block device object structure block_device

The kernel uses the structure block_device instance to represent a block device object, such as an entire hard disk or a specific partition. If the structure represents a partition, its member bd_part points to the partition structure of the device. If the structure represents a device, its member bd_disk points to the general hard disk structure gendisk of the device.

When a user opens a block device file, the kernel creates an instance of the structure block_device, and the device driver will also create an instance of the structure gendisk, allocate a request queue and register an instance of the structure block_device.

The block device object structure block_device is listed as follows (in include/linux/fs.h)

struct block_device {
    dev_t bd_dev;    /* not a kdev_t - it's a search key */
    struct inode *bd_inode; /* 分区节点 */
    struct super_block *bd_super;
    int bd_openers;
    struct mutex bd_mutex; /* open/clos mutex 打开与关闭的互斥量 */
    struct semaphore bd_mount_sem; /* 挂载操作信号量 */
    struct list_head bd_inodes;
    void *bd_holder;
    int bd_holders;
    #ifdef CONFIG_SYSFS
        struct list_head bd_holder_list;
    #endif
    struct block_device *bd_contains;
    unsigned bd_block_size; /* 分区块大小 */
    struct hd_struct *bd_part;
    unsigned bd_part_count; /* 打开次数 */
    int bd_invalidated;
    struct gendisk *bd_disk; /* 设备为硬盘是,指向通用硬盘结构 */
    struct list_head bd_list;
    struct backing_dev_info *bd_inode_backing_dev_info;
    unsigned long bd_private;
    /* The counter of freeze processes */
    int bd_fsfreeze_cout;
    /* Mutex for freeze */
    struct mutex bd_fsfreeze_mutex;
};

 

General hard disk structure gendisk

The structure gendisk represents a generic hard disk object, which stores information about a hard disk, including request queues, partition linked lists, and block device operation function sets. The block device driver allocates the structure gendisk instance, loads the partition table, allocates the request queue and fills the other fields of the structure.

The block driver supporting the partition must include the <linux/genhd.h> header file and declare a structure gendisk. The kernel also maintains a global linked list gendisk_head of the structure instance, and maintains the linked list through the functions add_gendisk, del_gendisk and get_gendisk.

The structure gendisk is listed as follows (in inlude/linux/genhd.h):

struct gendisk {
    int major; /* 驱动程序的主设备号 */
    int first_minor; /* 第一个次设备号 */
    int minors; /* 次设备号的最大数量,没有分区的设备,此值为1 */
    char disk_name[32]; /* 主设备号驱动程序的名字 */
    struct hd_struct **part; /* 分区列表,由次设备号排序 */
    struct block_device_operations *fops; /* 块设备操作函数集 */
    struct request_queue *queue; /* 请求队列 */
    struct blk_scsi_cmd_filter cmd_filter;
    void *private_data; /* 私有数据 */
    sector_t capacity; /* 函数 set_capacity 设置的容量,以扇区为单位 */
    int flags; /* 设置驱动器状态的标志,如:可移动介质为 GENHD_FL_REMOVABLE */
    struct device dev; /* 从设备驱动模型基类结构device继承 */
    struct kobject *holder_dir; 
    struct kobject *slave_dir;
    struct timer_rand_state *random;
    int policy;
    atomic_t sync_io; /* RAID */
    unsigned long stamp;
    int in_flight; 

    #ifdef CONFIG_SMP
        struct disk_stats *dkstats;
    #else
    /* 硬盘统计信息,如:读或写的扇区数、融合的扇区数、在请求队列的时间等 */
        struct disk_stats dkstats;
    #endif

    struct work_struct async_notify;

    #ifdef CONFIG_BLK_DEV_INTEGRITY
        struct blk_integrity *integrity; /* 用于数据完整性扩展 */
    #endif
};

 

The Linux kernel provides a set of functions to operate gendisk, including:

Allocate gendisk:
        struct gendisk *alloc_disk(int minors); The
        minors parameter is the number of minor device numbers used by this disk, which is generally the number of disk partitions. Minors cannot be modified afterwards.

Add gendisk: After the
        gendisk structure is allocated, the system cannot use the disk. You need to call the following function to register the disk device:
        void add_disk(struct gendisk *gd);
        especially note that the call to add_disk() must occur in After the initialization of the driver is completed and the disk request can be responded to.

Release gendisk:
        When a disk is no longer needed, use the following function to release gendisk:
        void del_gendisk(struct gendisk *gd);

Set the gendisk capacity:
        void set_capacity(struct gendisk *disk, sector_t size); The
        smallest addressable unit in a block device is a sector. The sector size is generally an integer multiple of 2, and the most common size is 512 bytes. The size of a sector is the physical attribute of the device. The sector is the basic unit of all block devices. A block device cannot be compared to its smaller unit for addressing and operation. However, many block devices can transmit multiple sectors at once. Although the sector size of most block devices is 512 bytes, sectors of other sizes are also common. For example, many CD-ROM disks have sectors of 2K in size. Regardless of the actual sector size of the physical device, the sectors that the kernel interacts with the block device driver are in units of 512 bytes. Therefore, the set_capacity() function also uses 512 bytes as a unit.

The partition structure hd_struct represents a partition object, which stores the information of a partition of a hard disk. When the driver is initialized, the partition information is extracted from the partition table of the hard disk and stored in the partition structure instance.

Block device operation function set structure block_device_operations

Character devices make their operations available to the system through the file_operations operation structure. A similar structure used on block devices is struct block_device_operations, defined in <linux/fs.h>.

int (*open)(struct inode *inode, struct file *filp);

int (*release)(struct inode *inode, struct file *filp);

Functions that work like their character-driven counterparts; they are called whenever the device is opened and closed. A character driver may respond to an open call by starting the device or locking the door (for removable media). If you lock the media into the device, of course you should unlock it in the release method.

int (*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);

Method to implement ioctl system call. However, the block layer first interprets a large number of standard requests; therefore, most block-driven ioctl methods are fairly short.

PS: There is no function to actually read or write data in block_device_operations. In the block I/O subsystem, these operations are handled by the request function.

Request structure request

The structure request represents a pending I/O request. Each request is described by a structure request instance , stored in the request pair list, and sorted by the elevator algorithm. Each request contains one or more structure bio instances .

struct request {
    // 用于挂在请求队列链表的节点,使用函数 blkdev_dequeue_request 访问它,而不是直接访问
    struct list_head queuelist;
    struct list_head donelist; /* 用于挂载已完成请求链表的节点 */
    struct request_queue *q; /* 指向请求队列 */
    unsigned int cmd_flags; /* 命令标识 */
    /* 各种各样的扇区计数 */
    /* 为提交 i/o 维护 bio 横断面的状态信息,hard_*成员是块层内部使用的,驱动程序不应该改变它们 */
    sector_t sector; /* 将提交的下一个扇区 */
    sector_t hard_sector; /* 将完成的下一个扇区 */
    unsigned long nr_sectors; /* 整个请求还需要传送的扇区数 */
    unsigned long hard_nr_sectors; /* 将完成的扇区数 */
    /* 在当前 bio 中还需要传送的扇区数 */
    unsigned int current_nr_sectors;
    /* 在当前段中将完成的扇区数 */
    unsigned int hard_cur_sectors;
    struct bio *bio; /* 请求中第一个未完成操作的 bio */
    struct bio *biotail; /* 请求链表中末尾的 bio */
    struct hlist_node hash; /* 融合 hash */
    /* rb_node 仅用在 I/O 调度器中,当请求被移到分发队列中时,请求将被删除。因此,让 completion_data 与 rb_node 分享空间 */
    union {
        struct rb_node rb_node; /* 排序/查找 */
        void *completion_data;
    }
};

The main members of the request structure include:

sector_t hard_sector;

unsigned long hard_nr_sectors;

unsigned int hard_cur_sectors;

The above three members identify sectors that have not yet been completed, hard_sector is the first sector that has not yet been transferred, hard_nr_sectors is the number of sectors yet to be completed, and hard_cur_sectors is the number of sectors to be completed in the current I/O operation. These members are only used at the kernel block device layer, and drivers should not use them.

sector_t hard_sector;

unsigned long hard_nr_sectors;

unsigned int current_nr_sectors;

The driver will often deal with these three members, and these three members play a major role in the interaction between the kernel and the driver. They use 512 bytes as a sector. If the hardware sector size is not 512 bytes, you need to adjust accordingly. For example, if the sector size of the hardware is 2048 bytes, you need to divide the sector number by 4 before proceeding with the hardware operation.

The relationship between hard_sector, hard_nr_sectors, hard_cur_sectors and sector, nr_sectors, current_nr_sectors can be regarded as a "copy" relationship.

struct bio *bio;

bio is a linked list of the bio structure contained in this request. It is not appropriate to directly access this member in the driver, but should use rq_for_each_bio() which will be introduced later.

 

Request queue structure request_queue

Each block device has a request queue, and each request queue performs I/O scheduling separately . The request queue is a doubly linked list linked by the request structure instance. The linked list and the information of the entire queue are described by the structure request_queue, which is called the request queue object Structure or request queue structure. It stores information about pending requests and information needed to manage the request queue (such as elevator algorithm) . The structure member request_fn is the request processing function from the device driver.

The request queue structure request_queue is listed below (in /include/linux/blk_dev.h)

It’s too long, here is a little bit, but I don’t understand it,--#

Bio structure

Usually one bio corresponds to one I/O request , and the IO scheduling algorithm can merge consecutive bios into one request. Therefore, one request can contain multiple bios.

The basic container for block I/O operations in the kernel is represented by the bio structure, which is defined in <linux/bio.h>. This structure represents the current (active) block I organized in the form of a segment linked list. /O operation. A fragment is a small contiguous memory buffer. The advantage of this is that there is no need to ensure that a single buffer must be continuous. Therefore, the buffer is described by fragments. Even if a buffer is scattered in multiple locations in the memory, the bio structure can guarantee the execution of I/O operations to the kernel. This is called vergence I/O. bio is the main data structure of the general layer, which not only describes the location of the disk, but also the location of the memory. It is the connection link between the upper kernel vfs and the lower driver.

struct bio {
    sector_t bi_sector; //该bio结构所要传输的第一个(512字节)扇区:磁盘的位置
    struct bio *bi_next; //请求链表
    struct block_device *bi_bdev; //相关的块设备
    unsigned long bi_flags; //状态和命令标志
    unsigned long bi_rw; //读写
    unsigned short bi_vcnt; //bio_vesc 偏移的个数
    unsigned short bi_idx; //bi_io_vec 的当前索引
    unsigned short bi_phys_segments; //结合后的片段数目
    unsigned short bi_hw_segments; //重映射后的片段数目
    unsigned int bi_size; //I/O计数
    unsinged int bi_hw_front_size; //第一个可合并的段大小
    unsinged int bi_hw_back_size; //最后一个可合并的段大小
    unsigned int bi_max_vecs; //bio_vecs 数目上限
    struct bio_vec *bi_io_vec; //bio_vec 链表:内存的位置
    bio_end_io_t *bi_end_io; //I/O 完成方法
    atomic_t bi_cnt; //使用计数
    void *bi_private; //拥有者的私有方法
    bio_destructor_t *bi_destructor; //销毁方法
};

 

Memory data segment structure bio_vec

The structure bio_vec represents a data segment in memory, and the data segment is described by page, offset, and length. The memory location where I/O needs to be executed is represented by segments, and the structure bio points to an array of segments. The structure bio_vec is listed as follows (in include/linux/bio.h):

The relationship between the various structures of the block device

 

 

 

 

 

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/u014674293/article/details/104407609