linux0.12-9-2-blk.h

[398 pages]

9-2 blk.h file

9-2-1 Functional Description

This is the header file related to hard disk block device parameters. Because it is only used for block devices, it is placed in the same place as the block device code. It mainly defines the data structure request of the items in the request waiting queue, defines the elevator search algorithm with macro statements, and corresponds to the virtual disk, hard disk and floppy disk three block devices currently supported by the kernel according to their respective major device numbers constant value.

Regarding the specific meaning of the extern inline function defined in this file, the description in the GNU C manual is as follows:

9-2-2 Code comments

#ifndef _BLK_H
#define _BLK_H

#define NR_BLK_DEV 7// Number of block device types.
/*
 * NR_REQUEST defined below is the number of items contained in the request queue.
 * Note that write operations only use the low-end 2/3 of these items; read operations take precedence.
 *
 * 32 items seems like a reasonable number: enough to benefit from the elevator algorithm,
 * But it does not appear to be a large number when the buffer is locked in the queue. 64 looks too
 * Big (can easily cause long pauses when a lot of write/sync operations are running).
 */
#define NR_REQUEST 32

/*
* OK, the following is an extended form of the request structure, so when implemented, we
* You can use the same request structure in the pagination request. In pagination processing,
* 'bh' is NULL, and 'waiting' is used to wait for read/write completion.
*/
// Below is the structure of the items in the request queue. Among them, if the field dev = -1, it means that the item in the queue is not used.
// The field cmd can be a constant READ (0) or WRITE (1) (defined in include/linux/fs.h).
// Among them, the kernel does not use the waiting pointer, instead the kernel uses the waiting queue of the buffer block. because
// Waiting for a buffer block is equivalent to waiting for a request item to complete.
struct request {<!-- -->
int dev; /* -1 if no request */ // The device number that sent the request.
int cmd; /* READ or WRITE */ // READ or WRITE command.
int errors; //The number of errors generated during operation.
unsigned long sector; // The starting sector. (1 block=2 sectors)
unsigned long nr_sectors; // Number of read/write sectors.
char * buffer; // data buffer.
struct task_struct * waiting; // where the task waits for the request to complete the operation (queue).
struct buffer_head * bh; // buffer head pointer (include/linux/fs.h,68).
struct request * next; // Point to the next request item.
};

/*
* The following definition is used for the elevator algorithm: Note that read operations are always performed before write operations.
* This is natural: read operations are much more time-critical than write operations.
*/
// The values of the parameters s1 and s2 in the macro below are pointers to the request structure request defined above. This macro is defined to be used according to two parameters
// Information in the specified request item structure (command cmd (READ or WRITE), device number dev, and sector number operated)
// To determine the order of the two request item structures. This order will be used as the request item execution order when accessing the block device.
// This macro will be called in the function add_request() in the program blk_drv/ll_rw_blk.c (line 96). The macro part
// Completely realize the I/O scheduling function, that is, realize the sorting function of request items (the other is the request item merging function).
#define IN_ORDER(s1,s2) \
((s1)->cmd<(s2)->cmd || (s1)->cmd==(s2)->cmd & amp; & amp; \
((s1)->dev < (s2)->dev || ((s1)->dev == (s2)->dev & amp; & amp; \
(s1)->sector < (s2)->sector)))

// Block device handling structure.
struct blk_dev_struct {<!-- -->
void (*request_fn)(void); // request processing function pointer.
struct request * current_request; // currently processed request structure.
};
// Block device table (array). Each block device occupies one item, a total of 7 items.
extern struct blk_dev_struct blk_dev[NR_BLK_DEV];
// Request queue array, a total of 32 items.
extern struct request request[NR_REQUEST];
// The head pointer of the queue of processes waiting for idle request items.
extern struct task_struct * wait_for_request;
// An array of pointers to the total number of device data blocks. Each pointer item points to the array hd_sizes[] of the total block number of the specified major device number. The total
// Each item of the block number array corresponds to the total number of data blocks owned by a sub-device determined by the sub-device number (1 block size = 1KB).
extern int * blk_size[NR_BLK_DEV];

// When the block device driver (such as hd.c) includes this header file, the major device number of the device that the driver handles must be defined first.
// In this way, the correct macro definition can be given for the driver program containing this file in the following lines 63-90.
#ifdef MAJOR_NR

/*
* Add entries as needed. Currently block devices only support hard disks and floppy disks (and also virtual disks).
*/
// If MAJOR_NR = 1 (RAM disk major device number) is defined, the following symbolic constants and macros are used.
#if (MAJOR_NR == 1)
/* ram disk */
#define DEVICE_NAME "ramdisk" // Device name ("ramdisk").
#define DEVICE_REQUEST do_rd_request // Device request item processing function.
#define DEVICE_NR(device) ((device) & amp; 7) // Device number (0 - 7).
#define DEVICE_ON(device) // Turn on the device (the virtual disk does not need to be turned on and off).
#define DEVICE_OFF(device) // Turn off the device.

// Otherwise, if MAJOR_NR = 2 (floppy drive major device number) is defined, the following symbolic constants and macros are used.
#elif (MAJOR_NR == 2)
/* floppy */
#define DEVICE_NAME "floppy" // Device name ("floppy drive").
#define DEVICE_INTR do_floppy // Device interrupt handler.
#define DEVICE_REQUEST do_fd_request // Device request item processing function.
#define DEVICE_NR(device) ((device) & amp; 3) // Device number (0 – 3).
#define DEVICE_ON(device) floppy_on(DEVICE_NR(device)) // Turn on the device macro.
#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) // Close device macro.

// Otherwise, if MAJOR_NR = 3 (hard disk major device number) is defined, the following symbolic constants and macros are used.
#elif (MAJOR_NR == 3)
/*harddisk*/
#define DEVICE_NAME "harddisk" // Device name ("hard disk").
#define DEVICE_INTR do_hd // Device interrupt handler.
#define DEVICE_TIMEOUT hd_timeout // Device timeout value.
#define DEVICE_REQUEST do_hd_request // Device request item processing function.
#define DEVICE_NR(device) (MINOR(device)/5) // Device number.
#define DEVICE_ON(device) // Turn on the device.
#define DEVICE_OFF(device) // Turn off the device.

// Otherwise, an error message is displayed during the compilation preprocessing stage: "unknown block device".
#elif
/* unknown blk device */
#error "unknown blk device"

#endif

// For the convenience of programming, two macros are defined here: CURRENT is the current request structure item pointer specifying the device number,
// CURRENT_DEV is the device number in the current request item CURRENT.
#define CURRENT (blk_dev[MAJOR_NR].current_request)
#define CURRENT_DEV DEVICE_NR(CURRENT->dev)

// If the device interrupt processing symbol constant is defined, declare it as a function pointer and default to NULL.
#ifdef DEVICE_INTR
void (*DEVICE_INTR)(void) = NULL;
#endif

// If the device timeout symbol constant is defined, make its value equal to 0, and define the SET_INTR() macro. Otherwise just define the macro.
#ifdef DEVICE_TIMEOUT
int DEVICE_TIMEOUT = 0;
#define SET_INTR(x) (DEVICE_INTR = (x),DEVICE_TIMEOUT = 200)
#else
#define SET_INTR(x) (DEVICE_INTR = (x))
#endif

// Declare the device request symbol constant DEVICE_REGUEST is a static function pointer with no parameters and no return.
static void (DEVICE_REQUEST)(void);

// Unlock the specified buffer block.
// If the specified buffer block bh is not locked, a warning message will be displayed. Otherwise, unlock the buffer block and wake up to wait
// The process of the buffer block. This is an inline function. The parameter is the buffer block header pointer.
extern inline void unlock_buffer(struct buffer_head * bh)
{<!-- -->
if (!bh->b_lock)
printk(DEVICE_NAME ": free buffer being unlocked\
");
bh->b_lock=0;
wake_up( & bh->b_wait);
}
// End request processing.
// The parameter uptodate is the update flag.
// First close the specified block device, and then check whether the read and write buffer is valid. If valid, set the buffer according to the parameter value
// Zone data update flag, and unlock the buffer. If the update flag parameter value is 0, it means that the operation of this request item has failed
// Failed, so the related block device IO error message is displayed. Finally, wake up the process waiting for the request item and wait for the idle request
// The process where the item appears, release and delete this request item from the request list, and point the current request item pointer to the next request item.
extern inline void end_request(int uptodate)
{<!-- -->
DEVICE_OFF(CURRENT->dev); // Turn off the device.
if (CURRENT->bh) {<!-- --> // CURRENT is the current request structure item pointer.
CURRENT->bh->b_uptodate = uptodate; // Set the update flag.
unlock_buffer(CURRENT->bh); // Unlock the buffer.
}
if (!uptodate) {<!-- --> // If the update flag is 0, an error message will be displayed.
printk(DEVICE_NAME "I/O error\
\r");
printk("dev x, block %d\
\r", CURRENT->dev,
CURRENT->bh->b_blocknr);
}
wake_up( & amp;CURRENT->waiting); // Wake up the process waiting for the request item.
wake_up( & amp;wait_for_request); // Wake up the process waiting for an idle request item.
CURRENT->dev = -1; // Release the request item.
CURRENT = CURRENT->next; // Point to the next request item.
}

// If the device timeout symbol constant DEVICE_TIMEOUT is defined, then define the CLEAR_DEVICE_TIMEOUT symbol constant
// is "DEVICE_TIMEOUT = 0". Otherwise define CLEAR_DEVICE_TIMEOUT to be empty.
#ifdef DEVICE_TIMEOUT
#define CLEAR_DEVICE_TIMEOUT DEVICE_TIMEOUT = 0;
#else
#define CLEAR_DEVICE_TIMEOUT
#endif

// If the device interrupt symbol constant DEVICE_INTR is defined, then define the CLEAR_DEVICE_INTR symbol constant as
// "DEVICE_INTR = 0", otherwise define it as empty.
#ifdef DEVICE_INTR
#define CLEAR_DEVICE_INTR DEVICE_INTR = 0;
#else
#define CLEAR_DEVICE_INTR
#endif


// Define the initialization request item macro.
// Since several block device drivers have similar initialization operations on request items at the beginning, here is a definition for them
// Unified initialization macro. This macro is used to make some validity judgments on the current request item. The work done is as follows:
// If the current request item of the device is empty (NULL), it means that the device currently has no request item to process. So a little sweep
// work and exit the corresponding function. Otherwise, if the major number of the device in the current request entry is not equal to the driver-defined major
// Backup number, indicating that the request item queue is messed up, so the kernel displays an error message and shuts down. Otherwise, if the buffer block used in the request item
// If it is not locked, it also means that there is a problem with the kernel program, so an error message is displayed and the system shuts down.
#define INIT_REQUEST \
repeat: \
if (!CURRENT) {<!-- -->\ // Return if the current request item pointer is NULL.
CLEAR_DEVICE_INTR\
CLEAR_DEVICE_TIMEOUT\
return; \
} \
if (MAJOR(CURRENT->dev) != MAJOR_NR) \ // If the current device major device number is incorrect, stop.
panic(DEVICE_NAME ": request list destroyed"); \
if (CURRENT->bh) {<!-- --> \
if (!CURRENT->bh->b_lock) \ // Stop if the buffer of the request item is not locked.
panic(DEVICE_NAME ": block not locked"); \
}

#endif

#endif