EmbLogic's Blog

The gendisk interface in Block driver

In 2.6 kernel the gendisk is at the core of the block subsystem; if you need to work with or find something out about a disk, struct gendisk probably has what you need.
The best way of looking at the contents of a gendisk structure from a block driver’s point of view is to examine what that driver must do to set the structure up in the first place. If your driver makes a disk (or disk-like) device available to the system, it will have to provide an associated gendisk structure. The first step is to create the gendisk structure itself; the function you need is alloc_disk() .
struct gendisk *alloc_disk(int minors);
The argument minors is the maximum number of minor numbers that this disk can have. Minor numbers correspond to partitions.If a single minor number is requested, the device cannot be partitioned at all.
There are several fields of the gendisk structure which must be initialized by the block driver. They include:

int major;
The major number of this device; either a static major assigned to a specific driver, or one that was obtained dynamically from register_blkdev()

int first_minor;
The first minor device number corresponding to this disk. This number will be determined by how your driver divides up its minor number space.

char disk_name[32];
The name of this disk (i.e. hda). This name is used in places like /proc/partitions and in creating a sysfs directory for the device.

struct block_device_operations *fops;
The device operations (open, release, ioctl, media_changed, and revalidate_disk) for this device. Each disk has its own set of operations in 2.6.

struct request_queue *queue;
The request queue which will handle the list of pending operations for this disk. The queue must be created and initialized separately.

int flags;
A set of flags controlling the management of this device. They include GENHD_FL_REMOVABLE for removable devices, GENHD_FL_CD for CDROM devices, and GENHD_FL_DRIVERFS which certainly means something interesting, but which is not actually used anywhere.

void *private_data;
This field is reserved for the driver; the rest of the block subsystem will not touch it. Usually it holds a pointer to a driver-specific data structure describing this device.

The gendisk structure also holds the size of the disk, in sectors. As part of the initialization process, the driver should set that size with:

void set_capacity(struct gendisk *disk, sector_t size);

The size value should be in 512-byte sectors, even if the hardware sector size used by your device is different. For removable disks, setting its capacity to zero indicates to the block subsystem that there is currently no media present in the device. Once you have your gendisk structure set up, you have to add it to the list of active disks; that is done with:

void add_disk(struct gendisk *disk);

After this call, your device is live.

There are a few things worth keeping in mind about add_disk():

–>add_disk() can create I/O to the device (to read partition tables and such). You should not call add_disk() until your driver is sufficiently initialized to handle requests.

–> If you are calling add_disk() in your driver initialization routine, you should not fail the initialization process after the first call.

–> The call to add_disk() increments the disk’s reference count; if the disk structure is ever to be released, the driver is responsible for decrementing that count (with put_disk()).

To remove a disk from the system, that is accomplished with:

void del_gendisk(struct gendisk *disk);

This function cleans up all of the information associated with the given disk, and generally removes it from the system. After a call to del_gendisk(), no more operations will be sent to the given device. Your driver’s reference to the gendisk object remains, though; you must explicitly release it with:

void put_disk(struct gendisk *disk);
That call will cause the gendisk structure to be freed, as long as no other part of the kernel retains a reference to it.

Note–>sbd_request() uses the blk_fetch_request(), blk_rq_pos(), blk_rq_cur_sectors() and __blk_end_request_cur() functions rather than elv_next_request(), req->sector, req->current_nr_sectors and end_request() respectively. The structure of the loop also changes so we handle each sector from the request individually.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>