O'Reilly logo

Linux Device Drivers, Second Edition by Alessandro Rubini, Jonathan Corbet

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Quick Reference

The most important functions and macros used in writing block drivers are summarized here. To save space, however, we do not list the fields of struct request, struct buffer_head, or struct genhd, and we omit the predefined ioctl commands.

#include <linux/fs.h> , int register_blkdev(unsigned int major, const char *name, struct block_device_operations *bdops); , int unregister_blkdev(unsigned int major, const char *name);

These functions are in charge of device registration in the module’s initialization function and device removal in the cleanup function.

#include <linux/blkdev.h> , blk_init_queue(request_queue_t *queue, request_fn_proc *request); , blk_cleanup_queue(request_queue_t *queue);

The first function initializes a queue and establishes the request function; the second is used at cleanup time.

BLK_DEFAULT_QUEUE(major)

This macro returns a default I/O request queue for a given major number.

struct blk_dev_struct blk_dev[MAX_BLKDEV];

This array is used by the kernel to find the proper queue for a given request.

int read_ahead[]; , int max_readahead[][];

read_ahead contains block-level read-ahead values for every major number. A value of 8 is reasonable for devices like hard disks; the value should be greater for slower media. max_readahead contains filesystem-level read-ahead values for every major and minor number, and is not usually changed from the system default.

int max_sectors[][];

This array, indexed by both major and minor number, holds the maximum number of sectors that should be merged into a single I/O request.

int blksize_size[][]; , int blk_size[][]; , int hardsect_size[][];

These two-dimensional arrays are indexed by major and minor number. The driver is responsible for allocating and deallocating the row in the matrix associated with its major number. The arrays represent the size of device blocks in bytes (it usually is 1 KB), the size of each minor device in kilobytes (not blocks), and the size of the hardware sector in bytes.

MAJOR_NR , DEVICE_NAME , DEVICE_NR(kdev_t device) , DEVICE_INTR , #include <linux/blk.h>

These macros must be defined by the driver before it includes <linux/blk.h>, because they are used within that file. MAJOR_NR is the major number for the device, DEVICE_NAME is the name of the device to be used in error messages, DEVICE_NR returns the minor number of the physical device referred to by a device number, and DEVICE_INTR is a little-used symbol that points to the device’s bottom-half interrupt handler.

spinlock_t io_request_lock;

The spinlock that must be held whenever an I/O request queue is being manipulated.

struct request *CURRENT;

This macro points to the current request when the default queue is being used. The request structure describes a data chunk to be transferred and is used by the driver’s request function.

INIT_REQUEST; , end_request(int status);

INIT_REQUEST checks the next request on the queue and returns if there are no more requests to execute. end_request is called at the completion of a block request.

spinlock_t io_request_lock;

The I/O request lock must be held any time that the request queue is being manipulated.

struct request *blkdev_entry_next_request(struct list_head *head); , struct request *blkdev_next_request(struct request *req); , struct request *blkdev_prev_request(struct request *req); , blkdev_dequeue_request(struct request *req); , blkdev_release_request(struct request *req);

Various functions for working with the I/O request queue.

blk_queue_headactive(request_queue_t *queue, int active);

Indicates whether the first request in the queue is being actively processed by the driver or not.

void blk_queue_make_request(request_queue_t *queue, make_request_fn *func);

Provides a function to handle block I/O requests directly out of the kernel.

end_that_request_first(struct request *req, int status, char *name); , end_that_request_last(struct request *req);

Handle the stages of completing a block I/O request. end_that_request_last is only called when all buffers in the request have been processed—that is, when end_that_request_first returns 0.

bh->b_end_io(struct buffer_head *bh, int status);

Signals the completion of I/O on the given buffer.

int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg);

A utility function that implements most of the standard block device ioctl commands.

int check_disk_change(kdev_t dev);

This function checks to see if a media change has occurred on the given device, and calls the driver’s revalidate method if a change is detected.

#include<linux/gendisk.h> , struct gendisk; , struct gendisk *gendisk_head;

The generic hard disk allows Linux to support partitionable devices easily. The gendisk structure describes a generic disk; gendisk_head is the beginning of a linked list of structures describing all of the disks on the system.

void register_disk(struct gendisk *gd, int drive, unsigned minors, struct block_device_operations *ops, long size);

This function scans the partition table of the disk and rewrites genhd->part to reflect the new partitioning.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required