# 文件系統,第 9 部分:磁盤塊示例
> 原文:<https://github.com/angrave/SystemProgramming/wiki/File-System%2C-Part-9%3A-Disk-blocks-example>
## 正在施工??
## 請問您能解釋一下文件內容如何存儲在簡單的基于 i 節點的文件系統中的簡單模型嗎?
當然!要回答這個問題,我們將構建一個虛擬磁盤,然后編寫一些 C 代碼來訪問其內容。我們的文件系統將可用字節劃分為 inode 的空間和磁盤塊的更大空間。每個磁盤塊將為 4096 字節 -
```c
// Disk size:
#define MAX_INODE (1024)
#define MAX_BLOCK (1024*1024)
// Each block is 4096 bytes:
typedef char[4096] block_t;
// A disk is an array of inodes and an array of disk blocks:
struct inode[MAX_INODE] inodes;
block[MAX_BLOCK] blocks;
```
請注意,為了清楚起見,我們不會在此代碼示例中使用“unsigned”。我們的固定大小的 inode 將包含文件的大小(以字節為單位),權限,用戶,組信息,時間元數據。與問題最相關的是它還包括十個指向磁盤塊的指針,我們將使用這些指針來引用實際文件的內容!
```c
struct inode {
int[10] directblocks; // indices for the block array i.e. where to the find the file's content
long size;
// ... standard inode meta-data e.g.
int mode, userid,groupid;
time_t ctime,atime,mtime;
}
```
現在我們可以弄清楚如何讀取文件偏移量`position`的字節:
```c
char readbyte(inode*inode,long position) {
if(position <0 || position >= inode->size) return -1; // invalid offset
int block_count = position / 4096,offset = position % 4096;
// block count better be 0..9 !
int physical_idx = lookup_physical_block_index(inode, block_count );
// sanity check that the disk block index is reasonable...
assert(physical_idx >=0 && physical_idx < MAX_BLOCK);
// read the disk block from our virtual disk 'blocks' and return the specific byte
return blocks[physical_idx][offset];
}
```
我們的 lookup_physical_block 的初始版本很簡單 - 我們可以使用 10 個直接塊的表格!
```c
int lookup_physical_block_index(inode*inode, int block_count) {
assert(block_count>=0 && block_count < 10);
return inode->directblocks[ block_count ]; // returns an index value between [0,MAX_BLOCK)
}
```
這種簡單的表示是合理的,只要我們可以用十個塊表示所有可能的文件,即最多 40KB。大文件怎么樣?我們需要 inode 結構始終具有相同的大小,因此將現有的直接塊數組增加到 20 將大約是我們的 inode 大小的兩倍。如果我們的大多數文件需要少于 10 個塊,那么我們的 inode 存儲現在是浪費的。為了解決這個問題,我們將使用一個名為 _ 間接塊 _ 的磁盤塊來擴展指針數組。我們只需要這個文件&gt; 40KB
```c
struct inode {
int[10] directblocks; // if size<4KB then only the first one is valid
int indirectblock; // valid value when size >= 40KB
int size;
...
}
```
間接塊只是一個 4096 字節的常規磁盤塊,但我們將使用它來保存指向磁盤塊的指針。在這種情況下我們的指針只是整數,所以我們需要將指針強制轉換為整數指針:
```c
int lookup_physical_block_index(inode*inode, int block_count) {
assert(sizeof(int)==4); // Warning this code assumes an index is 4 bytes!
assert(block_count>=0 && block_count < 1024 + 10); // 0 <= block_count< 1034
if( block_count < 10)
return inode->directblocks[ block_count ];
// read the indirect block from disk:
block_t* oneblock = & blocks[ inode->indirectblock ];
// Treat the 4KB as an array of 1024 pointers to other disk blocks
int* table = (int*) oneblock;
// Look up the correct entry in the table
// Offset by 10 because the first 10 blocks of data are already
// accounted for
return table[ block_count - 10 ];
}
```
對于典型的文件系統,我們的索引值是 32 位,即 4 字節。因此,在 4096 字節中,我們可以存儲 4096/4 = 1024 個條目。這意味著我們的間接塊可以引用 1024 * 4KB = 4MB 的數據。通過前十個直接塊,我們可以容納最大 40KB + 1024 * 4KB = 4136KB 的文件。對于小于此值的文件,某些后續表條目可能無效。
對于更大的文件,我們可以使用兩個間接塊。然而,有一個更好的選擇,這將允許我們有效地擴展到大型文件。我們將包含一個雙間接指針,如果這還不夠三重間接指針。雙重間接指針意味著我們有一個 1024 個條目表到磁盤塊,用作 1024 個條目。這意味著我們可以參考 1024 * 1024 個磁盤數據塊。

(來源: [http://uw714doc.sco.com/en/FS_admin/graphics/s5chain.gif](http://uw714doc.sco.com/en/FS_admin/graphics/s5chain.gif) )
```c
int lookup_physical_block_index(inode*inode, int block_count) {
if( block_count < 10)
return inode->directblocks[ block_count ];
// Use indirect block for the next 1024 blocks:
// Assumes 1024 ints can fit inside each block!
if( block_count < 1024 + 10) {
int* table = (int*) & blocks[ inode->indirectblock ];
return table[ block_count - 10 ];
}
// For huge files we will use a table of tables
int i = (block_count - 1034) / 1024 , j = (block_count - 1034) % 1024;
assert(i<1024); // triple-indirect is not implemented here!
int* table1 = (int*) & blocks[ inode->doubleindirectblock ];
// The first table tells us where to read the second table ...
int* table2 = (int*) & blocks[ table1[i] ];
return table2[j];
// For gigantic files we will need to implement triple-indirect (table of tables of tables)
}
```
請注意,使用 double indirect 讀取字節需要 3 個磁盤塊讀取(兩個表和實際數據塊)。
- UIUC CS241 系統編程中文講義
- 0. 簡介
- #Informal 詞匯表
- #Piazza:何時以及如何尋求幫助
- 編程技巧,第 1 部分
- 系統編程短篇小說和歌曲
- 1.學習 C
- C 編程,第 1 部分:簡介
- C 編程,第 2 部分:文本輸入和輸出
- C 編程,第 3 部分:常見問題
- C 編程,第 4 部分:字符串和結構
- C 編程,第 5 部分:調試
- C 編程,復習題
- 2.進程
- 進程,第 1 部分:簡介
- 分叉,第 1 部分:簡介
- 分叉,第 2 部分:Fork,Exec,等等
- 進程控制,第 1 部分:使用信號等待宏
- 進程復習題
- 3.內存和分配器
- 內存,第 1 部分:堆內存簡介
- 內存,第 2 部分:實現內存分配器
- 內存,第 3 部分:粉碎堆棧示例
- 內存復習題
- 4.介紹 Pthreads
- Pthreads,第 1 部分:簡介
- Pthreads,第 2 部分:實踐中的用法
- Pthreads,第 3 部分:并行問題(獎金)
- Pthread 復習題
- 5.同步
- 同步,第 1 部分:互斥鎖
- 同步,第 2 部分:計算信號量
- 同步,第 3 部分:使用互斥鎖和信號量
- 同步,第 4 部分:臨界區問題
- 同步,第 5 部分:條件變量
- 同步,第 6 部分:實現障礙
- 同步,第 7 部分:讀者編寫器問題
- 同步,第 8 部分:環形緩沖區示例
- 同步復習題
- 6.死鎖
- 死鎖,第 1 部分:資源分配圖
- 死鎖,第 2 部分:死鎖條件
- 死鎖,第 3 部分:餐飲哲學家
- 死鎖復習題
- 7.進程間通信&amp;調度
- 虛擬內存,第 1 部分:虛擬內存簡介
- 管道,第 1 部分:管道介紹
- 管道,第 2 部分:管道編程秘密
- 文件,第 1 部分:使用文件
- 調度,第 1 部分:調度過程
- 調度,第 2 部分:調度過程:算法
- IPC 復習題
- 8.網絡
- POSIX,第 1 部分:錯誤處理
- 網絡,第 1 部分:簡介
- 網絡,第 2 部分:使用 getaddrinfo
- 網絡,第 3 部分:構建一個簡單的 TCP 客戶端
- 網絡,第 4 部分:構建一個簡單的 TCP 服務器
- 網絡,第 5 部分:關閉端口,重用端口和其他技巧
- 網絡,第 6 部分:創建 UDP 服務器
- 網絡,第 7 部分:非阻塞 I O,select()和 epoll
- RPC,第 1 部分:遠程過程調用簡介
- 網絡復習題
- 9.文件系統
- 文件系統,第 1 部分:簡介
- 文件系統,第 2 部分:文件是 inode(其他一切只是數據...)
- 文件系統,第 3 部分:權限
- 文件系統,第 4 部分:使用目錄
- 文件系統,第 5 部分:虛擬文件系統
- 文件系統,第 6 部分:內存映射文件和共享內存
- 文件系統,第 7 部分:可擴展且可靠的文件系統
- 文件系統,第 8 部分:從 Android 設備中刪除預裝的惡意軟件
- 文件系統,第 9 部分:磁盤塊示例
- 文件系統復習題
- 10.信號
- 過程控制,第 1 部分:使用信號等待宏
- 信號,第 2 部分:待處理的信號和信號掩碼
- 信號,第 3 部分:提高信號
- 信號,第 4 部分:信號
- 信號復習題
- 考試練習題
- 考試主題
- C 編程:復習題
- 多線程編程:復習題
- 同步概念:復習題
- 記憶:復習題
- 管道:復習題
- 文件系統:復習題
- 網絡:復習題
- 信號:復習題
- 系統編程笑話