3.3.1 Preparing to Install the Hard Disk File System by Process 1
3.3.1.3 Bind the Buffer Block with Request
After returning to the bread function, call ll_rw_block() to bind the buffer block with request, as shown in Figure 3.23.
The code is as follows:
//Code path:fs/buffer.c:
struct buffer_head * bread(int dev,int block) {
struct buffer_head * bh;
if (!(bh = getblk(dev,block)))
panic(“bread: getblk returned NULL\n”);
if (bh->b_uptodate)//the applied buffer block has not been update return bh;
ll_rw_block(READ,bh);
wait_on_buffer(bh);
if (bh->b_uptodate) return bh;
brelse(bh);
return NULL;
}
NULL b_next
free_list 153 154 155
b_next_free
b_prev_free Overview
Figure 3.22 Step 6.
Once inside the ll_rw_block function, first determine whether the device correspond- ing to the buffer block exists or the request function of this device is normal; if it is present and normal, the block buffer can be used. Call the make_request function and prepare to bind the buffer block with request. The code is as follows:
Kernel
Enable interrupt
0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF
Kernel code area Kernel data area
Table head Request[32]
Reading request
ROM BIOS and VGA
Step 1:
lock
Step 2:
hook up with request item
After executing ll_rw_block Before executing ll_rw_block
Request[32]
Process status
Process 0 Process 1
Ready Interruptible
Current process
Table head Reading request
Figure 3.23 Hang the buffer block with request.
Process 1 continues to execute; after entering the make_request function, first lock the buffer block to protect the buffer block from being used by other processes. As shown in the right side of Figure 3.23, the management structure that corresponds to the selected buffer block has been locked.
Then, apply for a free request and bind it with the selected buffer block. If the request is read, the entire request items can be used; if the request is written, only the first two- thirds of the request items can be used. Because user hope reading data faster. As shown in Figure 3.23, the last item of request[32] has been selected. Later, bind the buffer block with the request item and initialize every number of the request item.
The code is as follows:
//Code path:kernel/blk_dev/ll_rw_block.c:
void ll_rw_block(int rw, struct buffer_head * bh) {
unsigned int major;
if ((major = MAJOR(bh->b_dev)) > = NR_BLK_DEV || //NR_BLK_DEV is 7, Major device //number0-6,> = 7 means not exists
!(blk_dev[major].request_fn)) {
printk(“Trying to read nonexistent block-device\n\r”);
return;
}
make_request(major,rw,bh);
}
//Code path:kernel/blk_dev/ll_rw_block.c:
static inline void lock_buffer(struct buffer_head * bh) {
cli();
while (bh->b_lock) //now, it’s unlock
sleep_on(&bh->b_wait);
bh->b_lock = 1; //lock the buffer block
sti();
}
……
static void make_request(int major,int rw, struct buffer_head * bh)//
{
struct request * req;
int rw_ahead;
/* WRITEA/READA is special case - it is not really needed, so if the */
/* buffer is locked, we just forget about it, else it's a normal read */
if (rw_ahead = (rw == READA || rw == WRITEA)) { if (bh->b_lock)//now, it’s unlock
return;
if (rw == READA)//abandon pre-read, replaced by normal read/write rw = READ;
else
rw = WRITE;
}
if (rw! = READ && rw! = WRITE)
panic(“Bad block dev command, must be R/W/RA/WA”);
lock_buffer(bh); //lock
if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) { //now, it’s unused unlock_buffer(bh);
return;
} repeat:
/* we don't allow the write-requests to fill up the queue completely:
* we want some room for reads: they take precedence. The last third
* of the requests are only for reads.
*/
Call the add_request function to add this request item to the request item queue;
after entering add_request, first analyze the work situation of the hard disk and then set this request item as the current request item and call (dev->request_fn)(); that is, the do_hd_request function sent a read command to the hard disk. The corresponding rela- tion between the request item management structure and the do_hd_ request function is as shown in Figure 3.24.
The code is as follows:
if (rw == READ) //read request is from the end of request[32], write request //is from the 2/3 of request[32]
req = request+NR_REQUEST;
else
req = request+((NR_REQUEST*2)/3);
/* find an empty request */
while (— — req > = request) //find the free request item from end, dev was //initialized to -1 in blk_dev_init, namely, free if (req->dev<0) //find the free request item
break;
/* if none found, sleep on new requests: check for rw_ahead */
if (req < request) { if (rw_ahead) {
unlock_buffer(bh);
return;
}
sleep_on(&wait_for_request);
goto repeat;
}
/* fill up the request-info, and add it to the queue */
req->dev = bh->b_dev; //set the request item req->cmd = rw;
req->errors = 0;
req->sector = bh->b_blocknr<<1;
req->nr_sectors = 2;
req->buffer = bh->b_data;
req->waiting = NULL;
req->bh = bh;
req->next = NULL;
add_request(major+blk_dev,req);
}
//Code path:kernel/blk_dev/ll_rw_block.c:
static void add_request(struct blk_dev_struct * dev, struct request * req) {
struct request * tmp;
req->next = NULL;
cli();
if (req->bh)
req->bh->b_dirt = 0;
if (!(tmp = dev->current_request)) { dev->current_request = req;
sti();
(dev->request_fn)(); //do_hd_request()
return;
}
for (; tmp->next ; tmp = tmp->next) //the effect of elevator algorithm is //making the moving distance of magnetic //head of disk is minimum
if ((IN_ORDER(tmp,req) ||
!IN_ORDER(tmp,tmp->next)) &&
IN_ORDER(req,tmp->next)) break;
req->next = tmp->next; //bind the request item queue tmp->next = req;
sti();
}