Linux block device driver

  

block device is a concept of juxtaposition with character devices. The structure of these two types of devices is greatly different in Linux. In general, block device drivers are much more complicated than character device drivers. I/O operations show great differences, and buffering, I/O scheduling, request queues, etc. are all concepts related to block device drivers. This chapter will show you how to program Linux block device drivers. Section 13.1 analyzes the characteristics of block device I/O operations and compares the differences in I/O operations between character devices and block devices. Section 13.2 describes the structure of the Linux block device driver as a whole, and analyzes the main data structures, functions, and relationships. Sections 13.3 through 13.5 illustrate the block device driver module loading and unloading, opening and releasing, and ioctl() functions, respectively. Section 13.6 is very important. It describes the concept and usage of request queues on which block device I/O operations depend. Sections 13.2 and 13.3 to 13.6 are the relationship between the whole and the part. Sections 13.2 to 13.6 and 13.7 are iterative progressive relationships. On the basis of the contents explained in Sections 13.1 to 13.6, Section 13.7 summarizes the read and write process of the Linux device. Section 13.7 gives a concrete example of a block device driver, the RAMDISK driver. 13.1 I/O Operation Characteristics of Block Devices The difference between character devices and block device I/O operations is that a block device can accept input and return output only in block units, while character devices are in bytes. Most devices are character devices because they do not require buffering and do not operate at a fixed block size. The 2 blocks have corresponding buffers for I/O requests, so they can choose which order to respond to. Character devices do not need to be buffered and read and write directly. The order of adjusting read and write is great for storage devices because it is faster to read and write consecutive sectors than separate sectors. 3 character devices can only be read and written sequentially, and block devices can be accessed randomly. Although block devices are randomly accessible, for mechanical devices such as disks, sequentially organizing access to block devices can improve performance. As shown in Figure 13.1, requests for disks 1, 10, 3, 2 are adjusted to requests for 1, 2, 3, 10 to improve read and write performance. Note that for block devices such as SD cards and RAMDISK, there is no mechanical reason, and it is not necessary to make such adjustments. Figure 13.1 Adjusting the order of block device I/O operations 13.2 Linux block device driver structure 13.2.1 block_device_operations structure In the block device driver, there is a block_device_operations structure similar to the file_operations structure in the character device driver, which is a block. A collection of device operations, as defined in Listing 13.1. Listing 13.1 block_device_operations structure 1 struct block_device_operations2 {3 int(*open)(struct inode *, struct file*); //Open 4 int(*release)(struct inode *, struct file*); //release 5 int (*ioctl)(struct inode *, struct file *, unsigned, unsigned long); //ioctl6 long(*unlocked_ioctl)(struct file *, unsigned, unsigned long);7 long(*compat_ioctl)(struct file *, unsigned , unsigned long); 8 int(*direct_access)(struct block_device *, sector_t, unsigned long*); 9 int(*media_changed)(struct gendisk*); //Media changed? 10 int(*revalidate_disk)(struct gendisk*); //Make the media valid 11 int(*getgeo)(struct block_device *, struct hd_geometry*); //Fill the drive information 12 struct module *owner; //Module owner 13 }; The following analysis of its main member functions: Open and release int (*open) (struct inode * inode, struct file *filp); int (*release) (struct inode * inode, struct file *filp) Similar to character device drivers, they are called when the device is turned on and off. IO control int (*ioctl) (struct inode * inode, struct file *filp, unsigned int cmd, unsigned long arg); the above function is an implementation of the ioctl() system call, the block device contains a large number of standard requests, these standard requests It is handled by the Linux block device layer, so most block device-driven ioctl() functions are quite short. • Media change int (*media_changed) (struct gendisk *gd); is called by the kernel to check if the media in the drive has changed, and if so, returns a non-zero value, otherwise returns 0. This function is only available for drives that support removable media (non-mobile devices do not need to implement this method), and usually require a flag variable to indicate whether the media state has changed. • Make the media valid int (*revalidate_disk) (struct gendisk *gd); the revalidate_disk() function is called to respond to a media change, which gives the driver an opportunity to do the necessary work to get the new media ready. Get the drive information int (*getgeo)(struct block_device *, struct hd_geometry *); this function fills an hd_geometry structure based on the geometry of the drive. The hd_geometry structure contains information such as heads, sectors, and cylinders. • The module pointer struct module *owner; a pointer to the module that owns the struct, which is usually initialized to THIS_MODULE. 13.2.2 gendisk structure In the Linux kernel, a gendisk (general disk) structure is used to represent a separate disk device (or partition). The definition of this structure is shown in Listing 13.2. Listing 13.2 gendisk structure 1 struct gendisk2 {3 int major; /* main device number */4 int first_minor; /* first sub-device number */5 int minors; /* maximum number of sub-devices, if not partitioned , is 1*/6 char disk_name[32]; /* device name */7 struct hd_struct **part; /* partition information on disk */8 struct block_device_operations *fops; /* block device operation structure */9 struct request_queue *queue; /* request queue */10 void *private_data; /* private data */11 sector_t capacity; /* sector number, 512 bytes for 1 sector */12 13 int flags; 14 char Devfs_name[64];15 int number;16 struct device *driverfs_dev;17 struct kobject kobj;18 19 struct timer_rand_state *random;20 int policy;21 22 atomic_t sync_io; /* RAID */23 unsigned long stamp;24 int in_flight; 25 #ifdef CONFIG_SMP26 struct disk_stats *dkstats;27 #else28 struct disk_stats dkstats;29 #endif30 };major, first_minor and minors together represent the primary and secondary device numbers of the disk, and each primary disk of the same disk shares a major device number. The minor device number is different. Fops is block_device_operations, the set of block device operations described in the previous section. A queue is a pointer that the kernel uses to manage the I/O request queue for this device. Capacity indicates the capacity of the device, in units of 512 bytes. Private_data can be used to point to any private data on the disk, similar to the private_data of the character device driver file structure.

Copyright © Windows knowledge All Rights Reserved