国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

電腦之家 - 專(zhuān)業(yè)計(jì)算機(jī)基礎(chǔ)知識(shí)與電腦技術(shù)學(xué)習(xí)網(wǎng)站
分類(lèi)導(dǎo)航

電腦知識(shí)|網(wǎng)絡(luò)技術(shù)|電腦硬件|組裝電腦|軟件教程|

服務(wù)器之家 - 電腦之家 - 電腦知識(shí) - 讀取硬盤(pán)前的準(zhǔn)備工作有哪些?

讀取硬盤(pán)前的準(zhǔn)備工作有哪些?

2022-01-06 20:34低并發(fā)編程閃客sun 電腦知識(shí)

讀取硬盤(pán)數(shù)據(jù)到內(nèi)存中,是操作系統(tǒng)的一個(gè)基礎(chǔ)功能。讀取硬盤(pán)需要有塊設(shè)備驅(qū)動(dòng)程序,而以文件的方式來(lái)讀取則還有要再上面包一層文件系統(tǒng)。

讀取硬盤(pán)前的準(zhǔn)備工作有哪些?

讀取硬盤(pán)數(shù)據(jù)到內(nèi)存中,是操作系統(tǒng)的一個(gè)基礎(chǔ)功能。

讀取硬盤(pán)需要有塊設(shè)備驅(qū)動(dòng)程序,而以文件的方式來(lái)讀取則還有要再上面包一層文件系統(tǒng)。

把讀出來(lái)的數(shù)據(jù)放到內(nèi)存,就涉及到內(nèi)存中緩沖區(qū)的管理。

上面說(shuō)的每一件事,都是一個(gè)十分龐大的體系,我們今天的文章一個(gè)都不展開(kāi)講,哈哈。

我們就講講,讀取塊設(shè)備與內(nèi)存緩沖區(qū)之間的橋梁,塊設(shè)備請(qǐng)求項(xiàng)的初始化工作。

我們以 Linux 0.11 源碼為例,發(fā)現(xiàn)進(jìn)入內(nèi)核的 main 函數(shù)后不久,有這樣一行代碼。

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

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

  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. }
  7. }

這也太簡(jiǎn)單了吧?

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

我們看下 request 結(jié)構(gòu)體。

  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 NULL, and '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. };

注釋也附上了。

哎喲,這就有點(diǎn)頭大了,剛剛的函數(shù)雖然很短,但看到這個(gè)結(jié)構(gòu)體我們知道了,重點(diǎn)在這呢。

這也側(cè)面說(shuō)明了,學(xué)習(xí)操作系統(tǒng),其實(shí)把遇到的重要數(shù)據(jù)結(jié)構(gòu)牢記心中,就已經(jīng)成功一半了。比如主內(nèi)存管理結(jié)構(gòu) mem_map,知道它的數(shù)據(jù)結(jié)構(gòu)是什么樣子,其功能也基本就懂了。

收,繼續(xù)說(shuō)這個(gè) request 結(jié)構(gòu),這個(gè)結(jié)構(gòu)就代表了一次讀盤(pán)請(qǐng)求,其中:

dev 表示設(shè)備號(hào),-1 就表示空閑。

cmd 表示命令,其實(shí)就是 READ 還是 WRITE,也就表示本次操作是讀還是寫(xiě)。

errors 表示操作時(shí)產(chǎn)生的錯(cuò)誤次數(shù)。

sector 表示起始扇區(qū)。

nr_sectors 表示扇區(qū)數(shù)。

buffer 表示數(shù)據(jù)緩沖區(qū),也就是讀盤(pán)之后的數(shù)據(jù)放在內(nèi)存中的什么位置。

waiting 是個(gè) task_struct 結(jié)構(gòu),這可以表示一個(gè)進(jìn)程,也就表示是哪個(gè)進(jìn)程發(fā)起了這個(gè)請(qǐng)求。

bh 是緩沖區(qū)頭指針,這個(gè)后面講完緩沖區(qū)就懂了,因?yàn)檫@個(gè) request 是需要與緩沖區(qū)掛鉤的。

next 指向了下一個(gè)請(qǐng)求項(xiàng)。

這里有的變量看不懂沒(méi)關(guān)系。

不過(guò)我們倒是可以基于現(xiàn)有的重點(diǎn)參數(shù)猜測(cè)一下,比如讀請(qǐng)求時(shí),cmd 就是 READ,sector 和 nr_sectors 這倆就定位了所要讀取的塊設(shè)備(可以簡(jiǎn)單先理解為硬盤(pán))的哪幾個(gè)扇區(qū),buffer 就定位了這些數(shù)據(jù)讀完之后放在內(nèi)存的什么位置。

這就夠啦,想想看,這四個(gè)參數(shù)是不是就能完整描述了一個(gè)讀取硬盤(pán)的需求了?而且完全沒(méi)有歧義,就像下面這樣。

讀取硬盤(pán)前的準(zhǔn)備工作有哪些?

而其他的參數(shù),肯定是為了更好地配合操作系統(tǒng)進(jìn)行讀寫(xiě)塊設(shè)備操作嘛,為了把多個(gè)讀寫(xiě)塊設(shè)備請(qǐng)求很好地組織起來(lái)。這個(gè)組織不但要有這個(gè)數(shù)據(jù)結(jié)構(gòu)中 hb 和 next 等變量的配合,還要有后面的電梯調(diào)度算法的配合,僅此而已,先點(diǎn)到為止。

總之,我們這里就先明白,這個(gè) request 結(jié)構(gòu)可以完整描述一個(gè)讀盤(pán)操作。然后那個(gè) request 數(shù)組就是把它們都放在一起,并且它們又通過(guò) next 指針串成鏈表。

讀取硬盤(pán)前的準(zhǔn)備工作有哪些?

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

但講到這就結(jié)束的話(huà),很多同學(xué)可能會(huì)不太甘心,那我就簡(jiǎn)單展望一下,后面讀盤(pán)的全流程中,是怎么用到剛剛初始化的這個(gè) request[32] 結(jié)構(gòu)的。

讀操作的系統(tǒng)調(diào)用函數(shù)是 sys_read,源代碼很長(zhǎng),我給簡(jiǎn)化一下,僅僅保留讀取普通文件的分支,就是如下的樣子。

  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. // 校驗(yàn) buf 區(qū)域的內(nèi)存限制
  5. verify_area(buf,count);
  6. // 僅關(guān)注目錄文件或普通文件
  7. return file_read(inode,file,buf,count);
  8. }

看,入?yún)?fd 是文件描述符,通過(guò)它可以找到一個(gè)文件的 inode,進(jìn)而找到這個(gè)文件在硬盤(pán)中的位置。

讀取硬盤(pán)前的準(zhǔn)備工作有哪些?

另兩個(gè)入?yún)?buf 就是要復(fù)制到的內(nèi)存中的位置,count 就是要復(fù)制多少個(gè)字節(jié),很好理解。

鉆到 file_read 函數(shù)里繼續(xù)看。

  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;
  27. }

整體看,就是一個(gè) while 循環(huán),每次讀入一個(gè)塊的數(shù)據(jù),直到入?yún)⑺蟮拇笮∪孔x完為止。

直接看 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. }
  7. }

這個(gè)函數(shù)就是去讀某一個(gè)設(shè)備的某一個(gè)數(shù)據(jù)塊號(hào)的內(nèi)容,展開(kāi)進(jìn)去看。

  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;
  11. }

其中 getblk 先申請(qǐng)了一個(gè)內(nèi)存中的緩沖塊,然后 ll_rw_block 負(fù)責(zé)把數(shù)據(jù)讀入這個(gè)緩沖塊,進(jìn)去繼續(xù)看。

  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);
  27. }

看,這里就用到了剛剛說(shuō)的結(jié)構(gòu)咯。

具體說(shuō)來(lái),就是該函數(shù)會(huì)往剛剛的設(shè)備的請(qǐng)求項(xiàng)鏈表 request[32] 中添加一個(gè)請(qǐng)求項(xiàng),只要 request[32] 中有未處理的請(qǐng)求項(xiàng)存在,都會(huì)陸續(xù)地被處理,直到設(shè)備的請(qǐng)求項(xiàng)鏈表是空為止。

具體怎么讀盤(pán),就是與硬盤(pán) IO 端口進(jìn)行交互的過(guò)程了,可以繼續(xù)往里跟,直到看到一個(gè) hd_out 函數(shù)為止,本講不展開(kāi)了。

具體讀盤(pán)操作,后面會(huì)有詳細(xì)的章節(jié)展開(kāi)講解,本講你只需要知道,我們?cè)?main 函數(shù)的 init 系列函數(shù)中,通過(guò) blk_dev_init 為后面的塊設(shè)備訪(fǎng)問(wèn),提前建立了一個(gè)數(shù)據(jù)結(jié)構(gòu),作為訪(fǎng)問(wèn)塊設(shè)備和內(nèi)存緩沖區(qū)之間的橋梁,就可以了。

原文鏈接:https://mp.weixin.qq.com/s/pIbVY1XPCktxGogc4lI1Bw

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产精品久久久久久久久久大牛 | 一区二区三区欧美 | 国产精品国产三级国产aⅴ原创 | 天天干狠狠操 | 成年人在线看片 | 日韩一区二区在线电影 | 精品美女久久久 | 日韩一区二区三区视频 | 一区二区免费在线观看 | 日本三级不卡 | 群p在线观看 | 亚洲综合在线视频 | 91精品国产综合久久久久久 | 一区欧美 | 国产日韩视频 | 亚洲国产aⅴ精品一区二区 少妇一级片免费看 | 成人网免费看 | 99精品在线观看 | 视频一区 日韩 | 免费观看黄色av网站 | 国产精品美女在线观看 | 国产精品久久久久久久久久新婚 | 亚洲精品不卡 | 欧美精品网站 | 日韩高清国产一区在线 | 国产精品久久久久久久9999 | 国产欧美中文字幕 | 久久综合久久综合久久综合 | 久久久久一区 | 国产精品一区二区久久久 | 爱色影wwwcom| 日韩电影免费在线观看中文字幕 | 日韩av影片| 久久精品a一级国产免视看成人 | 亚洲午夜电影 | 国产一级片 | 极品一区 | 中文字幕在线播放一区 | 国产精品a久久久久 | 亚洲天堂影院 | 久久亚洲一区二区 |