By Nathaniel Dang, Konstantin Rogachyov, and Brian Wallerstein
Last lecture, we discussed the scenario in which we couldn't move a file from one directory to another without potentially losing the file. This was due to the fact that if the PG&E company were to cut the power during the move operation, this could result in the violation of one of the file system invariants, in particular one of the top three invariants (the fourth invariant is a "weak" invariant, resulting only in a space leak). This is a major robustness problem!
Reiterating the file system invariants again:
1) Every block must be used for a single purpose.
2) Every referenced block is initialized.
3) No referenced block is free.
4) Every unreferenced block is free (weak) (counts at most the number of links)
File System Ordering:
| 0 | 1 | 2 | 3 ... 9 | 10 ... 2047 | 2048 - 3191 Write Ahead Log | |||
|---|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Free Block Bitmap | Inode Data | File System Data | ||||
Sample Inode Block:
| 1 | |||
|---|---|---|---|
| Type: Directory Number of Links = 1 Direct[0] = 12 ... |
|||
Sample File System Setup:
| 0 | 1 | 2 | 3 ... 9 | 10...11 | 12 | 13 | .... | 20 | .... | 2047 | 2048 - 3191 Write Ahead Log | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Free Block Bitmap | Inodes | / | :-) | /sub | ||||||||
| Block 2 | Block 3 | Block 12 | Block 13 | Block 20 | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Free Data Blocks: 10, 11, 14 - 19, 21+ | 1 Type: Directory NumLinks = 1 Direct[0] = 12 ... | 2 Type: Reg File NumLinks = 1 Direct[0] = 13 ... | 3 Type: Directory NumLinks = 1 Direct[0] = 20 ... | Directory Entry 1 Name: Sub Inode: 3 | Directory Entry 2 Name: hello.txt Inode: 2 | ... | Data Block Data: :-) | Directory Entry 1 Name: Inode: 0 | ... | ||||
Let's try removing a file, the proper operations are:
A) Clear directory entry
B) Decrement link count
C) If the link count is 0, then mark the blocks as free.
Example: Removing hello.txt
| 0 | 1 | 2 | 3 ... 9 | 10...11 | 12 | 13 | .... | 20 | .... | 2047 | 2048 - 3191 Write Ahead Log | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Free Block Bitmap | Inodes | / | :-) | /sub | Clear Directory Entry | Decrement Link Count | Commit | |||||
| Block 2 | Block 3 | Block 12 | Block 13 | Block 20 | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Free Data Blocks: 10, 11, 14 - 19, 21+ | 1 Type: Directory NumLinks = 1 Direct[0] = 12 ... | 2 Type: Reg File NumLinks = 1 Direct[0] = 13 ... | 3 Type: Directory NumLinks = 1 Direct[0] = 20 ... | Directory Entry 1 Name: Sub Inode: 3 | Directory Entry 2 Name: hello.txt Inode: 2 | ... | Data Block Data: :-) | Directory Entry 1 Name: Inode: 0 | ... | ||||
A) Clear Directory Entry
Example: Removing hello.txt:
| 0 | 1 | 2 | 3 ... 9 | 10...11 | 12 | 13 | .... | 20 | .... | 2047 | 2048 - 3191 Write Ahead Log | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Free Block Bitmap | Inodes | / | :-) | /sub | | Decrement Link Count | Commit | |||||
| Block 2 | Block 3 | Block 12 | Block 13 | Block 20 | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Free Data Blocks: 10, 11, 14 - 19, 21+ | 1 Type: Directory NumLinks = 1 Direct[0] = 12 ... | 2 Type: Reg File NumLinks = 1 Direct[0] = 13 ... | 3 Type: Directory NumLinks = 1 Direct[0] = 20 ... | Directory Entry 1 Name: Sub Inode: 3 | Directory Entry 2 Name: Inode: | ... | Data Block Data: :-) | Directory Entry 1 Name: Inode: 0 | ... | ||||
B/C) Decrement Link Count and Free Blocks (if Number of Links = 0)
Example: Removing hello.txt:
| 0 | 1 | 2 | 3 ... 9 | 10...11 | 12 | 13 | .... | 20 | .... | 2047 | 2048 - 3191 Write Ahead Log | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Free Block Bitmap | Inodes | / | :-) | /sub | | | Commit | |||||
| Block 2 | Block 3 | Block 12 | | Block 20 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Free Data Blocks: 10, 11, 13, 14 - 19, 21+ | 1 Type: Directory NumLinks = 1 Direct[0] = 12 ... | 2 Type: Reg File NumLinks= Direct[0]= ... | 3 Type: Directory NumLinks = 1 Direct[0] = 20 ... | Directory Entry 1 Name: Sub Inode: 3 | Directory Entry 2 Name: Inode: 0 | ... | Data Block Data: JUNK | Directory Entry 1 Name: Inode: 0 | ... | |||||
After the commit is performed, the file is removed from the file system!
Question: What would have happened if we had performed step C) first and then PG&E decided to cut the power?
Answer: We would have violated the third invariant! We can see that we must be careful in choosing the order of operations.
Now, our goals in moving a file from one directory to another are:
1) Always preserve invariants 1-3.
2) No matter when a crash might occur, we want the file to exist under at least the old or new file name.
Steps for properly moving a file from one directory to another
A) Increment link count
B) Create new directory entry for the inode
C) Delete the old directory entry
D) Decrement the link count
Example: Moving hello.txt
| 0 | 1 | 2 | 3 ... 9 | 10...11 | 12 | 13 | .... | 20 | .... | 2047 | 2048 - 3191 Write Ahead Log | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Free Block Bitmap | inodes | / | :-) | /sub | Increment Link Count | Create sub\hello.txt | Delete The Old Directory Entry | Decrement The Link Count | Commit | ||||
| Block 2 | Block 3 | Block 12 | Block 13 | Block 20 | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Free Data Blocks: 10, 11, 14 - 19, 21+ | 1 Type: Directory NumLinks = 1 Direct[0] = 12 ... | 2 Type: Reg File NumLinks = 1 Direct[0] = 13 ... | 3 Type: Directory NumLinks = 1 Direct[0] = 20 ... | Directory Entry 1 Name: Sub Inode: 3 | Directory Entry 2 Name: hello.txt Inode: 2 | ... | Data Block Data: :-) | Directory Entry 1 Name: Inode: 0 | ... | ||||
A) Increment Link Count
Example: Moving hello.txt
| 0 | 1 | 2 | 3 ... 9 | 10...11 | 12 | 13 | .... | 20 | .... | 2047 | 2048 - 3191 Write Ahead Log | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Free Block Bitmap | inodes | / | :-) | /sub | | Create sub\hello.txt | Delete The Old Directory Entry | Decrement The Link Count | Commit | ||||
| Block 2 | Block 3 | Block 12 | Block 13 | Block 20 | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Free Data Blocks: 10, 11, 14 - 19, 21+ | 1 Type: Directory NumLinks = 1 Direct[0] = 12 ... | 2 Type: Reg File NumLinks = Direct[0] = 13 ... | 3 Type: Directory NumLinks = 1 Direct[0] = 20 ... | Directory Entry 1 Name: Sub Inode: 3 | Directory Entry 2 Name: hello.txt Inode: 2 | ... | Data Block Data: :-) | Directory Entry 1 Name: Inode: 0 | ... | ||||
B) Create New Directory Entry for the Inode
Example: Moving hello.txt
| 0 | 1 | 2 | 3 ... 9 | 10...11 | 12 | 13 | .... | 20 | .... | 2047 | 2048 - 3191 Write Ahead Log | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Free Block Bitmap | inodes | / | :-) | /sub | | | Delete The Old Directory Entry | Decrement The Link Count | Commit | ||||
| Block 2 | Block 3 | Block 12 | Block 13 | Block 20 | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Free Data Blocks: 10, 11, 14 - 19, 21+ | 1 Type: Directory NumLinks = 1 Direct[0] = 12 ... | 2 Type: Reg File NumLinks = 2 Direct[0] = 13 ... | 3 Type: Directory NumLinks = 1 Direct[0] = 20 ... | Directory Entry 1 Name: Sub Inode: 3 | Directory Entry 2 Name: hello.txt Inode: 2 | ... | Data Block Data: :-) | Directory Entry 1 Name: hello.txt Inode: | ... | ||||
C) Delete the Old Directory Entry
Example: Moving hello.txt
| 0 | 1 | 2 | 3 ... 9 | 10...11 | 12 | 13 | .... | 20 | .... | 2047 | 2048 - 3191 Write Ahead Log | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Free Block Bitmap | inodes | / | :-) | /sub | | | | Decrement The Link Count | Commit | ||||
| Block 2 | Block 3 | Block 12 | Block 13 | Block 20 | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Free Data Blocks: 10, 11, 14 - 19, 21+ | 1 Type: Directory NumLinks = 1 Direct[0] = 12 ... | 2 Type: Reg File NumLinks = 2 Direct[0] = 13 ... | 3 Type: Directory NumLinks = 1 Direct[0] = 20 ... | Directory Entry 1 Name: Sub Inode: 3 | Directory Entry 2 Name: Inode: | ... | Data Block Data: :-) | Directory Entry 1 Name: hello.txt Inode: 2 | ... | ||||
D) Decrement the Link Count
Example: Moving hello.txt
| 0 | 1 | 2 | 3 ... 9 | 10...11 | 12 | 13 | .... | 20 | .... | 2047 | 2048 - 3191 Write Ahead Log | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Free Block Bitmap | inodes | / | :-) | /sub | | | | | Commit | ||||
| Block 2 | Block 3 | Block 12 | Block 13 | Block 20 | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Free Data Blocks: 10, 11, 14 - 19, 21+ | 1 Type: Directory NumLinks = 1 Direct[0] = 12 ... | 2 Type: Reg File NumLinks = Direct[0] = 13 ... | 3 Type: Directory NumLinks = 1 Direct[0] = 20 ... | Directory Entry 1 Name: Sub Inode: 3 | Directory Entry 2 Name: Inode: 0 | ... | Data Block Data: :-) | Directory Entry 1 Name: hello.txt Inode: 2 | ... | ||||
After the commit is performed, hello.txt has been moved from the root directory to root/subdir!
One Idea: Recover lost space by running a file system checker program.
Another Idea: Put the file systems operations in a LOG.
GOLDEN RULE OF ATOMICITY: Never modify the only copy of a file.
To create atomicity for file system operations, MAKE A COPY!
Write Ahead Logging:
IDEMPOTENT Operations: The result is the same no matter how many times the operation is applied.
Example:
Step One:
| 0 | 1 | 2 - 3 | 4 | 5 | 6 ... 2047 | ||
|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Block Bitmap | 1 | 2 | Decrement contents of Block 5 (A) | Increment contents of Block 4 (B) | Commit |
Step Two:
| 0 | 1 | 2 - 3 | 4 | 5 | 6 ... 2047 | ||
|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Block Bitmap | 2 | | | Increment contents of Block 4 (B) | Commit |
Step Three:
| 0 | 1 | 2 - 3 | 4 | 5 | 6 ... 2047 | ||
|---|---|---|---|---|---|---|---|
| Boot Sector | Super Block | Block Bitmap | | 1 | New Block #5 is 1 (A) | | Commit |
Even if a crash occurs, it's okay because the correct results are in the log anyway!
We want to ensure process memory isolation!
Robustness