磁盤的物理組成
-
盤面:
-
磁盤由多個盤面組成,每個盤面上都有數據存儲的區域。
-
-
磁道:
-
每個盤面上都有若干個同心圓,這些同心圓稱為磁道。磁道是數據存儲的路徑。
-
-
扇區:
-
磁道被進一步劃分為若干個扇區,扇區是磁盤的最小訪問單位。
-
扇區大小通常為512字節。
-
磁盤的io流程
該幻燈片描述了磁盤的輸入/輸出(I/O)過程,具體步驟如下:
-
開始使用磁盤:
-
首先,系統需要通過IDE控制器與磁盤建立連接,開始磁盤的I/O操作。
-
-
磁盤I/O過程:
-
磁盤的I/O過程包括以下幾個步驟:控制器、尋道、旋轉、傳輸。
-
-
尋道:
-
控制器發送指令,使磁頭移動到正確的磁道上。這是為了定位到數據所在的物理位置。
-
-
旋轉:
-
磁盤旋轉,使得目標扇區移動到磁頭下方。這個過程需要等待磁盤旋轉到正確的位置,可能會有一定的延遲。
-
-
傳輸:
-
一旦目標扇區位于磁頭下方,數據就可以從磁盤讀取到內存中,或者從內存寫入到磁盤中。
-
-
內存緩存:
-
讀取或寫入的數據首先會進入內存緩存。對于讀取操作,數據從磁盤讀出后存儲在內存緩存中;對于寫操作,數據首先寫入內存緩存,然后再從緩存寫入磁盤。
-
使用磁盤
柱面(Cylinder)
柱面是磁盤上所有盤面中具有相同徑向位置的磁道的集合。
當計算機需要讀取或寫入數據時,它會根據柱面號、磁頭號和扇區號來確定目標數據的位置。
通過控制磁頭的移動和盤片的旋轉,計算機可以準確地定位到特定柱面上的特定扇區,進行數據的讀寫操作。
磁頭(Head)
每個盤面對應一個磁頭。
所有的磁頭都是連在同一個磁臂上的,因此所有磁頭只能“共進退”。
每個磁頭上都有讀和寫的操作裝置,用于讀取和寫入數據。
磁頭臂是支持磁頭的可移動臂,通過電動機或電磁力控制,可以使磁頭在盤片上移動到不同的磁道位置。
扇區(Sector)
每個盤片被劃分為一個個磁道,每個磁道又劃分為一個個扇區。
扇區是磁盤的最小訪問單位,通常為512字節。
在讀取或寫入數據時,磁頭需要準確地定位到相應的扇區。磁盤驅動器在向磁盤讀取和寫入數據時,要以扇區為單位。
代碼分析
從提供的幻燈片內容中,我們可以提取出兩個函數的代碼,它們是 do_hd_request
和 hd_out
。以下是提取的代碼和總結:
提取的代碼
void do_hd_request(void) {...hd_out(dev, nsect, sec, head, cyl, WIN_WRITE, ...); // 調用hd_out函數port_write(HD_DATA, CURRENT->buffer, 256); // 將數據寫入硬盤
}
?
void hd_out(drive, nsect, sec, head, cyl, cmd...) {port = HD_DATA; // 數據寄存器端口(0x1f0)outb_p(nsect, ++port); // 輸出扇區數outb_p(sec, ++port); ? // 輸出起始扇區號outb_p(cyl, ++port); ? // 輸出柱面號outb_p(cyl >> 8, ++port); // 輸出柱面號的高字節outb_p(0xA0 | (drive << 4) | head, ++port); // 輸出驅動器和磁頭信息outb_p(cmd, ++port); // 輸出命令
}
代碼總結
-
do_hd_request
函數:-
這個函數處理硬盤的I/O請求。
-
它調用
hd_out
函數來設置硬盤控制器的參數,包括設備號(dev)、扇區數(nsect)、扇區號(sec)、磁頭號(head)、柱面號(cyl)等。 -
然后,它使用
port_write
函數將數據從內存緩沖區(CURRENT->buffer
)寫入硬盤,這里寫入的數據量為256字節。
-
-
hd_out
函數:-
這個函數負責將控制命令和參數輸出到硬盤控制器。
-
它首先設置數據寄存器端口(
HD_DATA
)。 -
然后,它使用
outb_p
函數依次輸出扇區數、扇區號、柱面號、柱面號的高字節、驅動器和磁頭信息以及命令。 -
這些參數用于控制硬盤的讀寫操作,例如移動磁頭到指定的柱面和磁頭位置,然后讀取或寫入指定的扇區。
-
這些代碼是磁盤驅動程序的核心部分,它們實現了操作系統與硬盤硬件之間的直接交互,是文件系統和數據存儲管理的基礎。
如何通過盤塊號讀寫磁盤
盤塊
盤塊(Block)是文件系統中用于數據存儲和管理的一個邏輯概念,它是文件系統中數據存儲的基本單位。盤塊是邏輯上的劃分,不同于磁盤物理結構中的扇區(Sector)、柱面(Cylinder)和磁頭(Head)等概念。以下是盤塊的詳細解釋:
-
盤塊號:
-
每個盤塊都有一個唯一的標識符,稱為盤塊號(Block Number)。盤塊號用于在文件系統中定位和訪問特定的盤塊。
-
-
盤塊與扇區的關系:
-
盤塊通常由一個或多個扇區組成。一個扇區是磁盤上最小的物理存儲單位,通常大小為512字節。
-
文件系統將一個或多個連續的扇區組合成一個盤塊,以提高數據管理的效率。
-
-
盤塊的分配:
-
文件系統使用盤塊分配表(Block Allocation Table, BAT)或inode(索引節點)等數據結構來記錄每個文件占用的盤塊信息。
-
當文件被創建或修改時,文件系統會分配新的盤塊或更新現有文件的盤塊信息。
-
-
盤塊的優缺點:
-
優點:簡化了文件數據的管理,提高了數據存儲和檢索的效率。
-
缺點:如果文件大小不是盤塊大小的整數倍,最后一個盤塊可能會有未使用的空間,導致一定的空間浪費。就是用空間換時間
-
為什么使用盤塊
-
磁盤訪問時間的組成:
-
磁盤訪問時間包括寫入控制器時間、尋道時間、旋轉時間和傳輸時間。
-
尋道時間:磁頭移動到目標磁道的時間,通常在12毫秒到8毫秒之間。
-
旋轉時間:磁盤旋轉到目標扇區的時間,對于7200轉/分鐘的硬盤,半周大約需要4毫秒。
-
傳輸時間:數據從磁盤傳輸到內存的時間,大約0.3毫秒(50MB/秒)。
-
-
盤塊相鄰的優勢:
-
相鄰的盤塊在物理位置上接近,因此可以快速連續讀出,減少了尋道時間和旋轉時間,提高了磁盤訪問效率
-
優點分析
-
提高效率:通過減少尋道時間和旋轉時間,提高了磁盤訪問的速度,從而提高了整體的系統性能。
-
抽象層次:操作系統通過提供這一層抽象,隱藏了磁盤的物理訪問細節,使得上層應用程序可以更加方便地使用磁盤資源。
如何編址?為什么這樣編址?
-
如何編址:磁盤驅動通過算法將盤塊號映射到CHS地址。這通常涉及到磁盤的幾何結構和盤塊的布局。
-
為什么這樣編址:這種編址方式是為了優化磁盤訪問效率。通過將相鄰的盤塊放在磁盤上的相鄰位置,可以減少尋道時間和旋轉時間,從而提高數據訪問速度。
扇區號的獲得
從CHS到扇區號
-
CHS地址轉換:磁盤的物理地址通常由柱面號(Cylinder)、磁頭號(Head)和扇區號(Sector)組成。幻燈片中提到的公式
Cx(HeadsxSectors) + HxSectors + S
用于計算從CHS地址到扇區號的轉換。-
C
:柱面號 -
Heads
:磁盤上的磁頭數 -
Sectors
:每個磁道上的扇區數 -
H
:磁頭號 -
S
:扇區號
-
磁盤請求的創建和處理過程
從提供的幻燈片內容中,我們可以提取出兩個函數的代碼,它們是 make_request
和 do_hd_request
。以下是提取的代碼和分析:
提取的代碼
// 創建一個磁盤請求
static void make_request()
{struct request *req;req = request + NR_REQUEST;req->sector = bh->b_blocknr << 1;add_request(major + blk_dev, req);
}
?
// 處理硬盤請求
void do_hd_request(void)
{unsigned int block = CURRENT->sector;asm volatile ("divl %4, %%eax;" ? ?// block / sect (每個磁頭的扇區數)"=a" (block), ? ? ? ?// 輸入:eax = 被除數"=d" (sec), ? ? ? ? ?// 輸出:edx = 余數(扇區號)"0" (block), ? ? ? ? // 輸入:eax = 被除數"1" (0), ? ? ? ? ? ? // 輸入:edx = 0(初始化為0)"r" (hd_info[dev].sect) // 輸入:ecx = 除數(每個磁頭的扇區數));asm volatile ("divl %4, %%eax;" ? ?// (block / sect) / head (磁頭數)"=a" (cyl), ? ? ? ? ?// 輸出:eax = 商(柱面號)"=d" (head), ? ? ? ? // 輸出:edx = 余數(磁頭號)"0" (block), ? ? ? ? // 輸入:eax = 被除數"1" (0), ? ? ? ? ? ? // 輸入:edx = 0(初始化為0)"r" (hd_info[dev].head) // 輸入:ecx = 除數(磁頭數));hd_out(dev, nsect, sec, head, cyl, WIN_WRITE, ...);...
}
代碼分析
-
make_request
函數:-
這個函數用于創建一個新的磁盤請求。
-
它分配一個新的請求結構體
req
,并設置請求的扇區號req->sector
。 -
bh->b_blocknr << 1
:將塊號左移一位,為了將塊號轉換為扇區號(假設每個塊由兩個扇區組成)。 -
add_request
:將新創建的請求添加到請求隊列中。
-
-
do_hd_request
函數:-
這個函數處理硬盤請求,將盤塊號轉換為CHS地址,并調用
hd_out
函數執行實際的磁盤操作。 -
CURRENT->sector
:獲取當前請求的扇區號。 -
使用內聯匯編(
asm volatile
)進行除法運算,將扇區號轉換為柱面號(cyl)、磁頭號(head)和扇區號(sec)。-
第一個除法運算計算扇區號(
sec
)。 -
第二個除法運算計算柱面號(
cyl
)和磁頭號(head
)。
-
-
hd_out
:執行實際的磁盤操作,包括尋道、旋轉和數據傳輸。
-
總結
這段代碼展示了Linux 0.11內核中磁盤請求的創建和處理過程。make_request
函數負責創建新的磁盤請求,而 do_hd_request
函數負責將盤塊號轉換為CHS地址,并執行實際的磁盤操作。
通過內聯匯編進行除法運算,實現了從盤塊號到CHS地址的轉換,這是磁盤驅動程序中的關鍵步驟。
多個進程使用磁盤
多進程通過隊列使用磁盤
-
請求隊列:
-
當多個進程需要訪問磁盤時,它們的請求被放入一個請求隊列中。這個隊列管理所有磁盤訪問請求,確保它們有序地被處理。
-
-
磁盤驅動:
-
磁盤驅動負責從請求隊列中取出請求,并將其轉換為磁盤控制器可以理解的CHS(柱面、磁頭、扇區)地址。
-
-
磁盤控制器:
-
磁盤控制器根據磁盤驅動提供的CHS地址執行實際的磁盤操作,如尋道、旋轉和數據傳輸。
-
磁盤調度
-
調度目標:
-
磁盤調度的主要目標是最小化平均訪問延遲。這意味著調度算法需要盡可能減少磁盤訪問請求的等待時間。
-
-
調度時主要考察的因素:
-
尋道時間:磁頭移動到目標磁道的時間,這是磁盤訪問時間中的主要部分。
-
旋轉時間:磁盤旋轉到目標扇區的時間。
-
傳輸時間:數據從磁盤傳輸到內存的時間。
-
-
調度算法:
-
FCFS(First-Come, First-Served):最簡單的調度算法,按照請求到達的順序處理。雖然公平,但可能不是最高效的,因為它不考慮磁頭的當前位置或請求的物理位置。
-
更復雜的算法:如SSTF(Shortest Seek Time First)、SCAN(Elevator Algorithm)等,這些算法試圖通過優化磁頭移動路徑來減少尋道時間,從而提高整體性能。
-
FCFS
-
最直觀、最公平的調度:
-
FCFS算法按照請求到達的順序處理,確保每個請求都能被公平地處理。
-
-
實例分析:
-
磁頭開始位置為53。
-
請求隊列為:98, 183, 37, 122, 14, 124, 65, 67。
-
-
磁頭移動:
-
FCFS算法導致磁頭共移動了640個磁道。
-
磁頭在移動過程中處理了經過的請求。
-
-
磁頭在長途奔襲:
-
圖中顯示了磁頭在處理請求時的移動路徑,磁頭需要在磁盤上進行大量的移動,這可能導致效率低下。
-
-
效率問題:
-
FCFS算法雖然公平,但可能導致磁頭在磁盤上進行大量的尋道操作,增加了尋道時間和旋轉時間,從而降低了磁盤的整體性能。
-
SSTF
SSTF(Shortest Seek Time First,最短尋道時間優先)磁盤調度算法。SSTF算法是一種優化磁盤訪問時間的算法,它選擇距離當前磁頭位置最近的請求進行處理,以減少磁頭移動的距離。以下是對幻燈片內容的分析:
-
算法原理:
-
SSTF算法選擇距離當前磁頭位置最近的請求進行處理,以減少尋道時間。
-
這種方法可以顯著減少磁頭移動的總距離,從而提高磁盤訪問效率。
-
-
實例分析:
-
磁頭開始位置為53。
-
請求隊列為:98, 183, 37, 122, 14, 124, 65, 67。
-
-
磁頭移動:
-
在這個實例中,SSTF算法導致磁頭共移動了236個磁道(4+53+169)。
-
相比FCFS算法的640個磁道,SSTF算法顯著減少了磁頭移動的距離。
-
-
效率提升:
-
通過優先處理距離當前磁頭位置最近的請求,SSTF算法可以更快地響應請求,減少等待時間。
-
-
饑餓問題:
-
SSTF算法存在饑餓問題,即遠離當前磁頭位置的請求可能會長時間得不到處理。
-
如果在處理183號請求之前,又來了一些中間磁道的請求,那么183號請求可能會被推遲處理,導致延遲。
-
SCAN
SCAN磁盤調度算法,也稱為電梯算法,它是一種常見的磁盤調度策略,旨在優化磁盤的尋道操作,減少尋道時間。
-
算法原理:
-
SCAN算法模擬電梯的運行方式,磁頭從一個方向開始移動,直到達到最后一個請求,然后改變方向,繼續處理另一方向的請求。
-
這種算法確保每個請求最終都會被處理,避免了SSTF算法中可能出現的饑餓問題。
-
-
實例分析:
-
磁頭開始位置為53。
-
請求隊列為:98, 183, 37, 122, 14, 124, 65, 67。
-
-
磁頭移動:
-
在這個實例中,SCAN算法導致磁頭共移動了236個磁道(53+183)。
-
與SSTF算法相比,SCAN算法在處理請求時更加公平,因為它確保了磁頭會遍歷所有請求。
-
-
公平性:
-
SCAN算法通過確保每個方向上的請求都被處理,提高了算法的公平性。
-
-
效率:
-
SCAN算法通過減少磁頭的來回移動,提高了磁盤訪問的效率。
-
與SSTF相比,SCAN算法在處理大量隨機分布的請求時,通常能提供更好的性能。
-
C-SCAN
這張幻燈片介紹了C-SCAN(Circular SCAN)磁盤調度算法,這是一種類似于電梯算法的磁盤調度策略,但在到達一端后直接移動到另一端,而不是改變方向。以下是對幻燈片內容的分析和總結:
-
算法原理:
-
C-SCAN算法從磁頭的當前位置開始,向一個方向移動,處理所有請求,到達磁盤的一端后,直接移動到另一端,然后繼續處理請求。
-
這種算法確保了兩端的請求都能被快速處理。
-
-
實例分析:
-
磁頭開始位置為53。
-
請求隊列為:98, 183, 37, 122, 14, 124, 65, 67。
-
-
磁頭移動:
-
在這個實例中,C-SCAN算法導致磁頭共移動了157+200個磁道。
-
其中200個磁道是磁頭從一端移動到另一端的距離,這個過程很快,因為它是連續的,沒有尋道時間。
-
-
效率:
-
C-SCAN算法通過直接從一端移動到另一端,減少了磁頭的尋道時間,提高了磁盤訪問的效率。
-
這種算法特別適合于請求分布均勻的情況,因為它可以確保所有請求都能被快速處理。
-
-
公平性:
-
C-SCAN算法在處理請求時,可能會對靠近磁頭起始位置的請求提供更快的服務,而對遠離起始位置的請求提供較慢的服務。
-
代碼實現
從提供的幻燈片內容中,我們可以提取出兩個函數的代碼:make_request
和 add_request
,以及一個宏定義 IN_ORDER
。以下是提取的代碼和總結:
提取的代碼
// 創建一個磁盤請求
static void make_request()
{struct request *req;req->sector = bh->b_blocknr << 1;add_request(major + blk_dev, req);
}
?
// 將請求添加到請求隊列
static void add_request(struct blk_dev_struct *dev, struct request *req)
{struct request *tmp = dev->current_request;req->next = NULL;cli(); // 關中斷(互斥)for (; tmp->next; tmp = tmp->next)if (IN_ORDER(tmp, req) || !IN_ORDER(tmp, tmp->next))&& IN_ORDER(req, tmp->next)) break;req->next = tmp->next; tmp->next = req; sti();
}
?
// 判斷請求是否有序
#define IN_ORDER(s1, s2) \((s1)->dev < (s2)->dev || \((s1)->dev == (s2)->dev && (s1)->sector < (s2)->sector))
代碼總結
-
make_request
函數:-
這個函數初始化一個新的磁盤請求,設置請求的扇區號
req->sector
,并將請求添加到磁盤請求隊列中。 -
bh->b_blocknr << 1
:假設每個塊由兩個扇區組成,因此將塊號左移一位來計算扇區號。
-
-
add_request
函數:-
這個函數將一個新的請求插入到磁盤請求隊列中,保持隊列的有序性。
-
使用
cli()
關閉中斷來確保在操作請求隊列時的互斥訪問。 -
通過
IN_ORDER
宏判斷請求是否有序,如果新請求應該插入到tmp
和tmp->next
之間,則進行插入。 -
使用
sti()
重新開啟中斷。
-
-
IN_ORDER
宏:-
這個宏用于判斷兩個請求是否有序,即是否按照設備號和扇區號的順序排列。
-
如果第一個請求的設備號小于第二個請求的設備號,或者設備號相同但扇區號小于第二個請求的扇區號,則認為有序。
-
總結如何使用生磁盤
這張幻燈片介紹了操作系統中生磁盤(raw disk)的使用流程,以及如何通過磁盤驅動程序來管理多個進程對磁盤的訪問。
-
進程獲取盤塊號:
-
進程首先需要獲取到要訪問的盤塊號(block number)。
-
-
計算扇區號:
-
根據盤塊號計算出對應的扇區號(sector number)。這通常涉及到將盤塊號映射到磁盤的物理地址。
-
-
創建請求并加入請求隊列:
-
使用計算出的扇區號創建一個磁盤請求(make req)。
-
將該請求加入到請求隊列中(add_request),可能使用電梯算法(SCAN算法)來優化請求的處理順序。
-
-
進程等待:
-
進程在發起磁盤請求后進入等待狀態(sleep_on)。
-
-
磁盤中斷處理:
-
當磁盤操作完成時,磁盤控制器會產生一個中斷信號。
-
中斷處理程序(read_intr)被觸發,喚醒等待的進程。
-
-
執行磁盤請求:
-
磁盤驅動程序處理請求(do_hd_request),計算出具體的柱面(cylinder)、磁頭(head)和扇區號(sector)。
-
-
端口寫入:
-
使用端口寫入操作(hd_out),通過outp函數將數據寫入磁盤控制器的端口,完成數據的實際讀寫操作。
-