成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

讀取硬盤前的準備工作有哪些?

存儲 存儲設備
讀取硬盤數據到內存中,是操作系統的一個基礎功能。讀取硬盤需要有塊設備驅動程序,而以文件的方式來讀取則還有要再上面包一層文件系統。

讀取硬盤數據到內存中,是操作系統的一個基礎功能。

讀取硬盤需要有塊設備驅動程序,而以文件的方式來讀取則還有要再上面包一層文件系統。

把讀出來的數據放到內存,就涉及到內存中緩沖區的管理。

上面說的每一件事,都是一個十分龐大的體系,我們今天的文章一個都不展開講,哈哈。

我們就講講,讀取塊設備與內存緩沖區之間的橋梁,塊設備請求項的初始化工作。

我們以 Linux 0.11 源碼為例,發現進入內核的 main 函數后不久,有這樣一行代碼。

  1. void main(void) { 
  2.     ... 
  3.     blk_dev_init(); 
  4.     ... 

看到這個方法的全部代碼后,你可能會會心一笑,也可能一臉懵逼。

  1. void blk_dev_init(void) { 
  2.     int i; 
  3.     for (i=0; i<32; i++) { 
  4.         request[i].dev = -1; 
  5.         request[i].next = NULL
  6.     } 

這也太簡單了吧?

就是給 request 這個數組的前 32 個元素的兩個變量 dev 和 next 附上值,看這倆值 -1 和 NULL 也可以大概猜出,這是沒有任何作用時的初始化值。

我們看下 request 結構體。

  1. /* 
  2.  * Ok, this is an expanded form so that we can use the same 
  3.  * request for paging requests when that is implemented. In 
  4.  * paging, 'bh' is NULLand 'waiting' is used to wait for 
  5.  * read/write completion. 
  6.  */ 
  7. struct request { 
  8.     int dev;        /* -1 if no request */ 
  9.     int cmd;        /* READ or WRITE */ 
  10.     int errors; 
  11.     unsigned long sector; 
  12.     unsigned long nr_sectors; 
  13.     char * buffer; 
  14.     struct task_struct * waiting; 
  15.     struct buffer_head * bh; 
  16.     struct request * next
  17. }; 

注釋也附上了。

哎喲,這就有點頭大了,剛剛的函數雖然很短,但看到這個結構體我們知道了,重點在這呢。

這也側面說明了,學習操作系統,其實把遇到的重要數據結構牢記心中,就已經成功一半了。比如主內存管理結構 mem_map,知道它的數據結構是什么樣子,其功能也基本就懂了。

收,繼續說這個 request 結構,這個結構就代表了一次讀盤請求,其中:

dev 表示設備號,-1 就表示空閑。

cmd 表示命令,其實就是 READ 還是 WRITE,也就表示本次操作是讀還是寫。

errors 表示操作時產生的錯誤次數。

sector 表示起始扇區。

nr_sectors 表示扇區數。

buffer 表示數據緩沖區,也就是讀盤之后的數據放在內存中的什么位置。

waiting 是個 task_struct 結構,這可以表示一個進程,也就表示是哪個進程發起了這個請求。

bh 是緩沖區頭指針,這個后面講完緩沖區就懂了,因為這個 request 是需要與緩沖區掛鉤的。

next 指向了下一個請求項。

這里有的變量看不懂沒關系。

不過我們倒是可以基于現有的重點參數猜測一下,比如讀請求時,cmd 就是 READ,sector 和 nr_sectors 這倆就定位了所要讀取的塊設備(可以簡單先理解為硬盤)的哪幾個扇區,buffer 就定位了這些數據讀完之后放在內存的什么位置。

這就夠啦,想想看,這四個參數是不是就能完整描述了一個讀取硬盤的需求了?而且完全沒有歧義,就像下面這樣。

而其他的參數,肯定是為了更好地配合操作系統進行讀寫塊設備操作嘛,為了把多個讀寫塊設備請求很好地組織起來。這個組織不但要有這個數據結構中 hb 和 next 等變量的配合,還要有后面的電梯調度算法的配合,僅此而已,先點到為止。

總之,我們這里就先明白,這個 request 結構可以完整描述一個讀盤操作。然后那個 request 數組就是把它們都放在一起,并且它們又通過 next 指針串成鏈表。

好,本文講述的兩行代碼,其實就完成了上圖所示的工作而已。

但講到這就結束的話,很多同學可能會不太甘心,那我就簡單展望一下,后面讀盤的全流程中,是怎么用到剛剛初始化的這個 request[32] 結構的。

讀操作的系統調用函數是 sys_read,源代碼很長,我給簡化一下,僅僅保留讀取普通文件的分支,就是如下的樣子。

  1. int sys_read(unsigned int fd,char * buf,int count) { 
  2.     struct file * file = current->filp[fd]; 
  3.     struct m_inode * inode = file->f_inode; 
  4.     // 校驗 buf 區域的內存限制 
  5.     verify_area(buf,count); 
  6.     // 僅關注目錄文件或普通文件 
  7.     return file_read(inode,file,buf,count); 

看,入參 fd 是文件描述符,通過它可以找到一個文件的 inode,進而找到這個文件在硬盤中的位置。

另兩個入參 buf 就是要復制到的內存中的位置,count 就是要復制多少個字節,很好理解。

鉆到 file_read 函數里繼續看。

  1. int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) { 
  2.     int left,chars,nr; 
  3.     struct buffer_head * bh; 
  4.     left = count
  5.     while (left) { 
  6.         if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) { 
  7.             if (!(bh=bread(inode->i_dev,nr))) 
  8.                 break; 
  9.         } else 
  10.             bh = NULL
  11.         nr = filp->f_pos % BLOCK_SIZE; 
  12.         chars = MIN( BLOCK_SIZE-nr , left ); 
  13.         filp->f_pos += chars; 
  14.         left -= chars; 
  15.         if (bh) { 
  16.             char * p = nr + bh->b_data; 
  17.             while (chars-->0) 
  18.                 put_fs_byte(*(p++),buf++); 
  19.             brelse(bh); 
  20.         } else { 
  21.             while (chars-->0) 
  22.                 put_fs_byte(0,buf++); 
  23.         } 
  24.     } 
  25.     inode->i_atime = CURRENT_TIME
  26.     return (count-left)?(count-left):-ERROR; 

整體看,就是一個 while 循環,每次讀入一個塊的數據,直到入參所要求的大小全部讀完為止。

直接看 bread 那一行。

  1. int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) { 
  2.     ... 
  3.     while (left) { 
  4.         ... 
  5.         if (!(bh=bread(inode->i_dev,nr))) 
  6.     } 

這個函數就是去讀某一個設備的某一個數據塊號的內容,展開進去看。

  1. struct buffer_head * bread(int dev,int block) { 
  2.     struct buffer_head * bh = getblk(dev,block); 
  3.     if (bh->b_uptodate) 
  4.         return bh; 
  5.     ll_rw_block(READ,bh); 
  6.     wait_on_buffer(bh); 
  7.     if (bh->b_uptodate) 
  8.         return bh; 
  9.     brelse(bh); 
  10.     return NULL

其中 getblk 先申請了一個內存中的緩沖塊,然后 ll_rw_block 負責把數據讀入這個緩沖塊,進去繼續看。

  1. void ll_rw_block(int rw, struct buffer_head * bh) { 
  2.     ... 
  3.     make_request(major,rw,bh); 
  4.  
  5. static void make_request(int major,int rw, struct buffer_head * bh) { 
  6.     ... 
  7. if (rw == READ
  8.         req = request+NR_REQUEST; 
  9.     else 
  10.         req = request+((NR_REQUEST*2)/3); 
  11. /* find an empty request */ 
  12.     while (--req >= request) 
  13.         if (req->dev<0) 
  14.             break; 
  15.     ... 
  16. /* fill up the request-info, and add it to the queue */ 
  17.     req->dev = bh->b_dev; 
  18.     req->cmd = rw; 
  19.     req->errors=0; 
  20.     req->sector = bh->b_blocknr<<1; 
  21.     req->nr_sectors = 2; 
  22.     req->buffer = bh->b_data; 
  23.     req->waiting = NULL
  24.     req->bh = bh; 
  25.     req->next = NULL
  26.     add_request(major+blk_dev,req); 

看,這里就用到了剛剛說的結構咯。

具體說來,就是該函數會往剛剛的設備的請求項鏈表 request[32] 中添加一個請求項,只要 request[32] 中有未處理的請求項存在,都會陸續地被處理,直到設備的請求項鏈表是空為止。

具體怎么讀盤,就是與硬盤 IO 端口進行交互的過程了,可以繼續往里跟,直到看到一個 hd_out 函數為止,本講不展開了。

 

具體讀盤操作,后面會有詳細的章節展開講解,本講你只需要知道,我們在 main 函數的 init 系列函數中,通過 blk_dev_init 為后面的塊設備訪問,提前建立了一個數據結構,作為訪問塊設備和內存緩沖區之間的橋梁,就可以了。

 

責任編輯:武曉燕 來源: 低并發編程
相關推薦

2018-01-25 16:23:58

JavaScript寫庫初始化

2013-02-27 10:35:03

RHEV 3.1

2013-05-16 15:04:55

系統升級

2009-03-01 22:27:21

2010-11-01 16:19:59

大型UPS電源準備工作

2011-03-25 10:25:19

2023-04-27 08:04:19

2010-05-19 13:45:41

IIS組件

2016-01-15 10:28:43

PaaS運維運維服務

2011-06-30 15:45:55

SEO

2017-03-09 19:19:18

重構應用開發架構

2011-07-06 11:10:30

iOS iphone XCode

2009-09-01 10:59:22

C#項目

2011-03-22 10:10:16

CentOSNagios安裝

2018-06-06 10:46:46

ERP

2011-08-01 14:08:17

admt活動目錄遷移

2009-07-23 12:22:41

ASP.NET MVC

2017-09-20 16:07:31

Facebook

2011-09-01 10:20:56

2010-02-26 15:46:31

MID Linux
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕 在线观看 | 国产免费又色又爽又黄在线观看 | 91精品国产色综合久久不卡98口 | 婷婷综合| 欧美区在线 | 国产网站在线免费观看 | 久久国产综合 | 精品视频在线免费观看 | 99视频免费在线 | 午夜精品一区二区三区在线观看 | 亚洲精品视频在线看 | 99精品久久久国产一区二区三 | 中文字幕一区在线观看视频 | 国产高清精品在线 | 精品欧美一区二区三区久久久 | www.日韩欧美 | 亚洲精品日韩精品 | 亚洲av毛片| 日韩免费视频一区二区 | 另类专区成人 | 国产激情视频网站 | 精品一区av | 亚洲网站在线播放 | 欧美8一10sex性hd | 国产日韩精品一区 | 久久精品a| 一本色道精品久久一区二区三区 | 欧美极品在线观看 | 免费成人午夜 | 99精品久久久国产一区二区三 | ww 255hh 在线观看 | 日韩在线免费观看视频 | 91精品国产综合久久久久久 | 波多野结衣一区二区三区 | 欧美日韩亚洲一区 | 午夜精品久久 | 免费视频一区二区 | 成人免费视频久久 | www亚洲成人| 日韩一区二区三区av | 成人免费视频在线观看 |