<ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>


      前言


      這個(gè)應(yīng)該是這個(gè)系列的尾聲了,一個(gè)完整的操作系統(tǒng)可能最主要的也就是分成這幾大模塊:進(jìn)程管理、內(nèi)存管理和文件系統(tǒng)。計(jì)算機(jī)以進(jìn)程為基本單位進(jìn)行資源的調(diào)度和分配;而與用戶的交互,基本單位則是文件

      生磁盤

      文件正是對(duì)生磁盤的抽象

      磁盤的組成

      一個(gè)磁盤由多個(gè)盤面串聯(lián)而成,而一個(gè)盤面又被分為磁道,磁道又由扇區(qū)組成。

      磁盤的訪問單元就是扇區(qū),一個(gè)扇區(qū)為512字節(jié)

      磁盤的使用

      * CPU向磁盤的控制器發(fā)出一個(gè)指令
      * 控制器開始進(jìn)行尋道、旋轉(zhuǎn)和傳輸
      * 最后完成后向CPU發(fā)送一個(gè)中斷
      也就是向控制器發(fā)送柱面磁頭扇區(qū)等信息,然后等待回應(yīng)

      盤塊

      盤塊是對(duì)扇區(qū)的抽象

      程序負(fù)責(zé)提高盤塊block,而磁盤驅(qū)動(dòng)負(fù)責(zé)從block計(jì)算出cyl,head,sec(CHS),最后傳遞到磁盤控制器上

      磁盤訪問時(shí)間 = 寫入控制器時(shí)間 + 尋道時(shí)間 + 旋轉(zhuǎn)時(shí)間 + 傳輸時(shí)間

      其中主要的時(shí)間都在尋道時(shí)間和旋轉(zhuǎn)時(shí)間,所以對(duì)扇區(qū)抽象成盤塊就可以一次訪問多個(gè)扇區(qū)來節(jié)省磁盤的訪問時(shí)間

      磁盤調(diào)度

      既然有多進(jìn)程交替執(zhí)行,就有可能多個(gè)進(jìn)程同時(shí)訪問相同磁盤的情況,就需要一個(gè)請(qǐng)求隊(duì)列來處理所有請(qǐng)求,就會(huì)涉及到調(diào)度算法了

      FCFS調(diào)度

      FCFS是最公平最直觀的算法,也就是按照隊(duì)列順序來訪問磁盤,但是效率也很低下,磁頭會(huì)在不規(guī)律的磁道長(zhǎng)途奔襲

      SSTF調(diào)度

      SSTF算法就類似短作業(yè)優(yōu)先算法,先尋找更近距離的磁道,但是SSTF算法可能會(huì)產(chǎn)生饑餓問題,過長(zhǎng)距離的磁道可能一直得不到處理

      SCAN調(diào)度

      SCAN算法就是SSTF算法的改良版,也就是進(jìn)行SSTF,但是在中途不會(huì)折返去尋找更短距離的磁道,這樣就避免了饑餓問題

      C-SCAN調(diào)度(電梯算法)

      把掃描限定在一個(gè)方向,當(dāng)訪問到某個(gè)方向的最后一個(gè)磁道時(shí),磁道返回磁盤相反方向磁道的末端,并再次開始掃描。



      文件和文件系統(tǒng)


      文件是對(duì)磁盤的第三層抽象,扇區(qū)和盤塊分別是前兩層抽象。之所以有文件這層抽象是為了方便用戶的使用,在用戶的眼里,磁盤上的信息都可以看作是字符流。所以文件的抽象九可以看作是字符流到盤塊集合的映射關(guān)系

      文件的邏輯結(jié)構(gòu)

      從文件到盤塊的映射來看,一般有這幾種組織方式

      *
      順序文件

      記錄是定長(zhǎng)的且按關(guān)鍵字順序排列??梢皂樞虼鎯?chǔ)或以鏈表形勢(shì)存儲(chǔ),在訪問時(shí)需要順序搜索文件。順序文件有以下兩種結(jié)構(gòu):

      *

      第一種是串結(jié)構(gòu),各記錄之間的順序與關(guān)鍵字無關(guān)。通常的辦法是由時(shí)間來決定,即按存入時(shí)間的先后排列,最先存入的記錄作為第一個(gè)記錄,其次存入的為第二個(gè)記錄,以此類推。

      *
      第二種是順序結(jié)構(gòu),指文件中所有記錄按關(guān)鍵字順序排列。

      在對(duì)記錄進(jìn)行批量操作時(shí),即每次要讀或?qū)懸淮笈涗?,?duì)順序文件的效率是所有邏輯文件中最高的;此外,也只有順序文件才能存儲(chǔ)在磁帶上,并能有效的工作。但順序文件對(duì)查找、修改、增加或刪除單個(gè)記錄的操作比較困難。

      *
      索引文件


      對(duì)于可變長(zhǎng)記錄的文件只能順序查找,系統(tǒng)開銷較大,為此可以建立一張索引表以加快檢索速度,索引表本身是順序文件。在記錄很多或是訪問要求高的文件中,需要引入索引以提供有效的訪問,實(shí)際中,通過索引可以成百上千倍的提高訪問速度。

      *
      索引順序表


      索引順序表是順序和索引兩種組織形勢(shì)的結(jié)合。索引順序文件將順序文件中所有記錄分為若干個(gè)組,為順序文件建立一張索引表,在索引表中為每組中的第一個(gè)記錄建立一個(gè)索引項(xiàng),其中含有該記錄的關(guān)鍵字值和指向該記錄的指針。

      在實(shí)際的操作系統(tǒng)實(shí)現(xiàn)中,一般是采用多級(jí)索引



      目錄和文件系統(tǒng)

      文件系統(tǒng)或者說目錄是對(duì)磁盤的第四個(gè)抽象,也就是抽象了整個(gè)磁盤

      操作系統(tǒng)為了實(shí)現(xiàn)文件目錄,引入了稱為文件控制塊的數(shù)據(jù)結(jié)構(gòu)。

      文件控制塊。


      文件控制塊(FCB)是用來存放控制文件需要的各種信息的數(shù)據(jù)結(jié)構(gòu),以實(shí)現(xiàn)“按名存取”。FCB的有序集合稱為文件目錄,一個(gè)FCB就是一個(gè)文件目錄項(xiàng)。為了創(chuàng)建一個(gè)新文件,系統(tǒng)將分配一個(gè)FCB并存放在文件目錄中,稱為目錄項(xiàng)。

      FCB主要包含以下信息:

      * 基本信息,如文件名、文件的物理位置、文件的邏輯結(jié)構(gòu)、文件的物理結(jié)構(gòu)等。
      * 存取控制信息,如文件的存取權(quán)限等。
      * 使用信息,如文件建立時(shí)間、修改時(shí)間等。
      文件目錄樹

      在多級(jí)目錄下一般對(duì)磁盤就可以抽象為

      *
      FCB數(shù)組

      FCB數(shù)組就是將所有盤塊的FCB信息都集中到一個(gè)數(shù)組中

      *
      數(shù)據(jù)盤塊集合

      在每個(gè)數(shù)據(jù)盤塊里都包含一些目錄項(xiàng)用來找到子目錄,目錄項(xiàng)也就是文件名+對(duì)應(yīng)的FCB的“地址”,也就是去之前的FCB數(shù)組中找到相應(yīng)的FCB

      在磁盤進(jìn)行格式化的時(shí)候,會(huì)存放一些信息用來知道一些磁盤信息和找到根目錄



      *
      inode位圖: 哪些inode空閑,哪些被占用

      *
      超級(jí)塊:記錄兩個(gè)位圖有多大等信息

      *
      盤塊位圖: 哪些盤塊是空閑的,硬盤大小不同這個(gè)位圖的大小也不同

      文件的實(shí)現(xiàn)

      在我之前實(shí)現(xiàn)的FragileOS <https://github.com/dejavudwh/FragileOS>
      里文件系統(tǒng)非常簡(jiǎn)陋,基本沒有什么好說的。這其實(shí)也是為什么之前把這個(gè)系列改了一個(gè)方向來結(jié)合的看Linux0.11的代碼。所以來看一下Linux0.11里是怎么使用和實(shí)現(xiàn)文件系統(tǒng)的,

      讀取文件

      * 這是讀取文件的系統(tǒng)調(diào)用
      * 函數(shù)首先對(duì)參數(shù)有效性進(jìn)行判斷
      * 之后對(duì)文件的類型進(jìn)行判斷
      * 如果是目錄文件或者是常規(guī)文件就執(zhí)行讀取操作 int sys_read(unsigned int fd,char * buf,int count) {
      struct file * file; struct m_inode * inode; if (fd>=NR_OPEN || count<0 ||
      !(file=current->filp[fd])) return -EINVAL; if (!count) return 0;
      verify_area(buf,count); inode = file->f_inode; if (inode->i_pipe) return
      (file->f_mode&1)?read_pipe(inode,buf,count):-EIO; if (S_ISCHR(inode->i_mode))
      return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos); if
      (S_ISBLK(inode->i_mode)) return
      block_read(inode->i_zone[0],&file->f_pos,buf,count); if (S_ISDIR(inode->i_mode)
      || S_ISREG(inode->i_mode)) { if (count+file->f_pos > inode->i_size) count =
      inode->i_size - file->f_pos; if (count<=0) return 0; return
      file_read(inode,file,buf,count); }
      printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode); return -EINVAL; }
      * 根據(jù)i節(jié)點(diǎn)和文件結(jié)構(gòu),讀取文件中數(shù)據(jù)。
      * 首先判斷參數(shù)的有效性
      * 之后循環(huán)的調(diào)用bread來讀取數(shù)據(jù)
      * 之后復(fù)制chars字節(jié)到用戶緩沖區(qū)buf中
      * 最后是修改該i節(jié)點(diǎn)的訪問時(shí)間為當(dāng)前時(shí)間和返回讀取的字節(jié)數(shù) int file_read(struct m_inode * inode, struct
      file * filp, char * buf, int count) { int left,chars,nr; struct buffer_head *
      bh; if ((left=count)<=0) return 0; 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; }
      文件寫入

      * 根據(jù)i節(jié)點(diǎn)和文件結(jié)構(gòu)信息,將用戶數(shù)據(jù)寫入文件中
      * 首先確定數(shù)據(jù)寫入文件的位置
      * 然后算出對(duì)應(yīng)的盤塊
      * 然后用戶緩沖區(qū)buf中復(fù)制c個(gè)字節(jié)到告訴緩沖塊中p指向的開始位置處
      * 最后是修改該i節(jié)點(diǎn)的訪問時(shí)間為當(dāng)前時(shí)間和返回讀取的字節(jié)數(shù) int file_write(struct m_inode * inode, struct
      file * filp, char * buf, int count) { off_t pos; int block,c; struct
      buffer_head * bh; char * p; int i=0; /* * ok, append may not work when many
      processes are writing at the same time * but so what. That way leads to madness
      anyway. */ if (filp->f_flags & O_APPEND) pos = inode->i_size; else pos =
      filp->f_pos; while (i<count) { if (!(block =
      create_block(inode,pos/BLOCK_SIZE))) break; if
      (!(bh=bread(inode->i_dev,block))) break; c = pos % BLOCK_SIZE; p = c +
      bh->b_data; bh->b_dirt = 1; c = BLOCK_SIZE-c; if (c > count-i) c = count-i; pos
      += c; if (pos > inode->i_size) { inode->i_size = pos; inode->i_dirt = 1; } i +=
      c; while (c-->0) *(p++) = get_fs_byte(buf++); brelse(bh); } inode->i_mtime =
      CURRENT_TIME; if (!(filp->f_flags & O_APPEND)) { filp->f_pos = pos;
      inode->i_ctime = CURRENT_TIME; } return (i?i:-1); }
      文件目錄的實(shí)現(xiàn)

      打開創(chuàng)建文件

      * 首先對(duì)參數(shù)進(jìn)行處理,然后搜索進(jìn)程結(jié)構(gòu)中文件結(jié)構(gòu)指針數(shù)組一個(gè)空閑的文件句柄
      * 接著為打開文件在文件表中尋找一個(gè)空閑結(jié)構(gòu)項(xiàng)
      * 然后調(diào)用函數(shù)open_namei()執(zhí)行打開操作,若返回值小于0,則說明出錯(cuò),就釋放剛申請(qǐng)到的文件結(jié)構(gòu)
      * 然后為不同的文件類型做一些特殊的處理
      * 最后初始化打開文件的文件結(jié)構(gòu),然后返回文件句柄 int sys_open(const char * filename,int flag,int
      mode) { struct m_inode * inode; struct file * f; int i,fd; mode &= 0777 &
      ~current->umask; for(fd=0 ; fd<NR_OPEN ; fd++) if (!current->filp[fd]) break;
      if (fd>=NR_OPEN) return -EINVAL; current->close_on_exec &= ~(1<<fd);
      f=0+file_table; for (i=0 ; i<NR_FILE ; i++,f++) if (!f->f_count) break; if
      (i>=NR_FILE) return -EINVAL; (current->filp[fd]=f)->f_count++; if
      ((i=open_namei(filename,flag,mode,&inode))<0) { current->filp[fd]=NULL;
      f->f_count=0; return i; } /* ttys are somewhat special (ttyxx major==4, tty
      major==5) */ if (S_ISCHR(inode->i_mode)) { if (MAJOR(inode->i_zone[0])==4) { if
      (current->leader && current->tty<0) { current->tty = MINOR(inode->i_zone[0]);
      tty_table[current->tty].pgrp = current->pgrp; } } else if
      (MAJOR(inode->i_zone[0])==5) if (current->tty<0) { iput(inode);
      current->filp[fd]=NULL; f->f_count=0; return -EPERM; } } /* Likewise with
      block-devices: check for floppy_change */ if (S_ISBLK(inode->i_mode))
      check_disk_change(inode->i_zone[0]); f->f_mode = inode->i_mode; f->f_flags =
      flag; f->f_count = 1; f->f_inode = inode; f->f_pos = 0; return (fd); }
      解析目錄

      * 先根據(jù)當(dāng)前路徑的第一個(gè)字符來判斷當(dāng)前路徑是絕對(duì)路徑還是相對(duì)路徑
      * 然后進(jìn)循環(huán)處理過程,分割每個(gè)目錄名
      * 得到這個(gè)目錄名后,調(diào)用查找目錄項(xiàng)函數(shù)find_entry()在當(dāng)前處理的目錄中尋找指定名稱的目錄
      * 如果找到這個(gè)目錄,就設(shè)置一些信息,然后繼續(xù)以該目錄項(xiàng)為當(dāng)前目錄繼續(xù)循環(huán)處理路徑名中的下一目錄名部分(或文件名) static struct
      m_inode * get_dir(const char * pathname) { char c; const char * thisname;
      struct m_inode * inode; struct buffer_head * bh; int namelen,inr,idev; struct
      dir_entry * de; if (!current->root || !current->root->i_count) panic("No root
      inode"); if (!current->pwd || !current->pwd->i_count) panic("No cwd inode"); if
      ((c=get_fs_byte(pathname))=='/') { inode = current->root; pathname++; } else if
      (c) inode = current->pwd; else return NULL; /* empty name is bad */
      inode->i_count++; while (1) { thisname = pathname; if (!S_ISDIR(inode->i_mode)
      || !permission(inode,MAY_EXEC)) { iput(inode); return NULL; }
      for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++) /* nothing */ ;
      if (!c) return inode; if (!(bh = find_entry(&inode,thisname,namelen,&de))) {
      iput(inode); return NULL; } inr = de->inode; idev = inode->i_dev; brelse(bh);
      iput(inode); if (!(inode = iget(idev,inr))) return NULL; } }

      友情鏈接
      ioDraw流程圖
      API參考文檔
      OK工具箱
      云服務(wù)器優(yōu)惠
      阿里云優(yōu)惠券
      騰訊云優(yōu)惠券
      京東云優(yōu)惠券
      站點(diǎn)信息
      問題反饋
      郵箱:[email protected]
      QQ群:637538335
      關(guān)注微信

        <ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>
          爱爱视频久久 | 日韩人妻一区二区 | 爱搞亚洲 | 国产午夜性爽视频男人的天堂 | 黄色AA级| 波多野结衣午夜影院 | 用鸡巴操逼操黄片操一级片 | 亚洲AV日韩AV无码裸体尤物 | 91精品久久久久久久久 | 中文AV网 |