其他
读取硬盘前的准备工作有哪些?
void main(void) {
...
blk_dev_init();
...
}
void blk_dev_init(void) {
int i;
for (i=0; i<32; i++) {
request[i].dev = -1;
request[i].next = NULL;
}
}
/*
* Ok, this is an expanded form so that we can use the same
* request for paging requests when that is implemented. In
* paging, 'bh' is NULL, and 'waiting' is used to wait for
* read/write completion.
*/
struct request {
int dev; /* -1 if no request */
int cmd; /* READ or WRITE */
int errors;
unsigned long sector;
unsigned long nr_sectors;
char * buffer;
struct task_struct * waiting;
struct buffer_head * bh;
struct request * next;
};
dev 表示设备号,-1 就表示空闲。
cmd 表示命令,其实就是 READ 还是 WRITE,也就表示本次操作是读还是写。
errors 表示操作时产生的错误次数。
sector 表示起始扇区。
nr_sectors 表示扇区数。
buffer 表示数据缓冲区,也就是读盘之后的数据放在内存中的什么位置。
waiting 是个 task_struct 结构,这可以表示一个进程,也就表示是哪个进程发起了这个请求。
bh 是缓冲区头指针,这个后面讲完缓冲区就懂了,因为这个 request 是需要与缓冲区挂钩的。
next 指向了下一个请求项。
int sys_read(unsigned int fd,char * buf,int count) {
struct file * file = current->filp[fd];
struct m_inode * inode = file->f_inode;
// 校验 buf 区域的内存限制
verify_area(buf,count);
// 仅关注目录文件或普通文件
return file_read(inode,file,buf,count);
}
int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) {
int left,chars,nr;
struct buffer_head * bh;
left = count;
while (left) {
if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) {
if (!(bh=bread(inode->i_dev,nr)))
break;
} else
bh = NULL;
nr = filp->f_pos % BLOCK_SIZE;
chars = MIN( BLOCK_SIZE-nr , left );
filp->f_pos += chars;
left -= chars;
if (bh) {
char * p = nr + bh->b_data;
while (chars-->0)
put_fs_byte(*(p++),buf++);
brelse(bh);
} else {
while (chars-->0)
put_fs_byte(0,buf++);
}
}
inode->i_atime = CURRENT_TIME;
return (count-left)?(count-left):-ERROR;
}
int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) {
...
while (left) {
...
if (!(bh=bread(inode->i_dev,nr)))
}
}
struct buffer_head * bread(int dev,int block) {
struct buffer_head * bh = getblk(dev,block);
if (bh->b_uptodate)
return bh;
ll_rw_block(READ,bh);
wait_on_buffer(bh);
if (bh->b_uptodate)
return bh;
brelse(bh);
return NULL;
}
void ll_rw_block(int rw, struct buffer_head * bh) {
...
make_request(major,rw,bh);
}
static void make_request(int major,int rw, struct buffer_head * bh) {
...
if (rw == READ)
req = request+NR_REQUEST;
else
req = request+((NR_REQUEST*2)/3);
/* find an empty request */
while (--req >= request)
if (req->dev<0)
break;
...
/* fill up the request-info, and add it to the queue */
req->dev = bh->b_dev;
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);
}
本文可以当做 你管这破玩意叫操作系统源码 系列文章的第 15 回。
为了让不追更系列的读者也能很方便阅读并学到东西,我把它改造成了单独的不依赖系列上下文的文章,具体原因可以看 坚持不下去了...
点击下方的阅读原文可以跳转到本系列的 GitHub 页,那里也有完整目录和规划,以及一些辅助的资料,欢迎提出各种问题。