The first two blog has been basically familiar with the structure of the block equipment, here to summarize the ldd3 mentioned in some of the block device drive examples;
1, registration: Register a block device driver to the kernel , is actually using the main device number to tell the kernel this representative block device driver
Sbull_major = Register_blkdev (sbull_major, "sbull"); if (0 >= sbull_major) { printk (kern_warning "Sbull: unable to get major Number!\n "); return -ebusy; }
2. Define the structure of the device:
struct sbull_dev{ int size;//sector unit, device size U8 *data;//data array short users;// number of users short Media_ Change Media change identification spinlock_t lock;//For Mutex struct request_queue *queue;//device request queue struct Gendisk *gd; Gendisk structure struct timer_list time;//used to simulate media changes};
3. Initialize the structure of the device:
memset (Dev, 0, sizeof (struct sbull_dev)); Dev->size = nsectors * hardsect_size; Dev->data = Vmalloc (dev->size); if (dev->data = = NULL) { PRINTK (kern_notice "Vmalloc failure.\n"); Return } spin_lock_init (&dev->lock);//Initialize the spin lock for the next queue assignment
4. Create the request queue for the device:
Dev->queue = Blk_init_queue (Sbull_request, &dev->lock);
5, the allocation, initialization and installation of the corresponding GENDISK structure:
DEV->GD = Alloc_disk (sbull_minors); if (!DEV->GD) { printk (kern_notice "Alloc_disk failure.\n"); Goto Out_vfree; } dev->gd->major = Sbull_major; Dev->gd->first_minor = which*sbull_minors; Dev->gd->fops = &sbull_ops; Dev->gd->queue = dev->queue; Dev->gd->private_data= Dev; snprintf (Dev->gd->disk_name, +, "sbull%c", which + ' a '); Set_capacity (DEV->GD, nsectors* (hardsect_size/kernel_sector_size));//using Kernel_sector_size Local constants, Perform a kernel 512-byte sector to the actual sector size conversion Add_disk (DEV->GD);
Sbull_minors is the number of secondary device numbers supported Per device, one device named Sbulla, and the second sbullb. User space can add partitions, and a third partition on the second device may be/dev/sbullb3.
6. Set the sector size supported by the queue
Notifies the kernel device of the supported sector size, and the hardware sector size is placed in the queue as a parameter, rather than in Gendisk. Call the following function immediately after assigning the queue:
Blk_queue_hardsect_size (Dev->queue, hardset_size);
Once the above function is called, the kernel will use the set hardware sector size for our device, all the I/O requests are located at the beginning of the hardware sector, and each request size will be an integer multiple of the sector size. Remember: The kernel always thinks that the sector size is 512 bytes, so you must convert all the number of sectors.
7. Implement the Operation function:
To open the device function:
static int Sbull_open (struct inode *inode, struct file *filp) { struct sbull_dev *dev = inode->i_bdev- >bd_disk->private_data; Del_timer_sync (&dev->timer);//Remove timer filp->private_data = dev; Spin_lock (&dev->lock); if (!dev->users) check_disk_change (Inode->i_bdev);//Check if the media in the drive changes dev->users++;//increase user Count Spin_unlock (&dev->lock); return 0; }
To turn off the device function:
static int sbull_release (struct inode *inode, struct file *filp) { struct sbull_dev *dev = inode->i_bdev- >bd_disk->private_data; Spin_lock (&dev->lock); dev->users--; if (!dev->users) { dev->timer.expires = jiffies + invalidate_delay;//Set timer add_timer (&dev-> timer); } Spin_unlock (&dev->lock); return 0; }
Other functions are implemented as well, similar to character device drivers. Here is not to write, next look at the core, for a block device driver is the core part of the request, almost all the center of gravity in the request function;
8. Handling Request operation
Dev->queue = Blk_queue_init (&sbull_request, &dev->lock); static void Sbull_request (request_queue _t *q) { struct request *req; while (req = Elv_next_ Request (q)) = null) {//Gets the first outstanding request in the queue, and returns null if none. Do not delete this request after processing struct Sbull_dev *dev = Req->rq_disk->private_data ; if (! blk_fs_request (req)) {//Determine if a file system request is not a block device request PRINTK (kern_notice "Skip non-fs request.\ n "); end_request (req, 0); continue; } The//sbull_transfer () function is a real processing block device request function Sbull_transfer (d EV, Req->sector, req->current_nr_sectors, req->buffer, Rq_data_dir (req)); end_request (req, 1); } } void end_request (struct request* req, int succeeded), //sector The index number of the start sector, Refers to a 512-byte sector, if it is a 2048-byte sector, then SECTOR/4//Nsect indicates how many sectors to pass, buffer data cache address pointer; Write indicates the direction of data passing, that is,:read/write; static void Sbull_transfer (struct Sbull_dev *dev, unsigned long sector, unsigned long nsect, char *buffer, int write)   ; { unsigned long offset = sector*kernel_sector_size; unsigned long Nbytes = nsect*kernel_sector_size; if (offset + nbytes) > Dev->size) { PRINTK (kern_notice "beyond-end write (%ld%ld) \ n", offset, nbytes); & nbsp; return; } if ( Write) memcpy (dev->data + offset, bUffer, nbytes); else memcpy (buffer, dev- >data + offset, nbytes); }
Reprint Address: Example of Linux block device driver
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Examples of Linux block device drivers