Bind the Buffer Block with Request

Một phần của tài liệu The art of linux kernel design (Trang 140 - 144)

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();

}

Một phần của tài liệu The art of linux kernel design (Trang 140 - 144)

Tải bản đầy đủ (PDF)

(524 trang)