1
- // File system implementation. Four layers:
1
+ // File system implementation. Five layers:
2
2
// + Blocks: allocator for raw disk blocks.
3
+ // + Log: crash recovery for multi-step updates.
3
4
// + Files: inode allocator, reading, writing, metadata.
4
5
// + Directories: inode with special contents (list of other inodes!)
5
6
// + Names: paths like /usr/rtm/xv6/fs.c for convenient naming.
6
7
//
7
- // Disk layout is: superblock, inodes, block in-use bitmap, data blocks.
8
- //
9
8
// This file contains the low-level file system manipulation
10
9
// routines. The (higher-level) system call implementations
11
10
// are in sysfile.c.
@@ -61,10 +60,10 @@ balloc(uint dev)
61
60
readsb (dev , & sb );
62
61
for (b = 0 ; b < sb .size ; b += BPB ){
63
62
bp = bread (dev , BBLOCK (b , sb .ninodes ));
64
- for (bi = 0 ; bi < BPB && bi < ( sb .size - b ) ; bi ++ ){
63
+ for (bi = 0 ; bi < BPB && b + bi < sb .size ; bi ++ ){
65
64
m = 1 << (bi % 8 );
66
65
if ((bp -> data [bi /8 ] & m ) == 0 ){ // Is block free?
67
- bp -> data [bi /8 ] |= m ; // Mark block in use on disk .
66
+ bp -> data [bi /8 ] |= m ; // Mark block in use.
68
67
log_write (bp );
69
68
brelse (bp );
70
69
bzero (dev , b + bi );
@@ -90,22 +89,27 @@ bfree(int dev, uint b)
90
89
m = 1 << (bi % 8 );
91
90
if ((bp -> data [bi /8 ] & m ) == 0 )
92
91
panic ("freeing free block" );
93
- bp -> data [bi /8 ] &= ~m ; // Mark block free on disk.
92
+ bp -> data [bi /8 ] &= ~m ;
94
93
log_write (bp );
95
94
brelse (bp );
96
95
}
97
96
98
97
// Inodes.
99
98
//
100
- // An inode is a single, unnamed file in the file system .
101
- // The inode disk structure holds metadata ( the type, device numbers ,
102
- // and data size) along with a list of blocks where the associated
103
- // data can be found .
99
+ // An inode describes a single unnamed file.
100
+ // The inode disk structure holds metadata: the file's type ,
101
+ // its size, the number of links referring to it, and the
102
+ // list of blocks holding the file's content .
104
103
//
105
104
// The inodes are laid out sequentially on disk immediately after
106
- // the superblock. The kernel keeps a cache of the in-use
107
- // on-disk structures to provide a place for synchronizing access
108
- // to inodes shared between multiple processes.
105
+ // the superblock. Each inode has a number, indicating its
106
+ // position on the disk.
107
+ //
108
+ // The kernel keeps a cache of in-use inodes in memory
109
+ // to provide a place for synchronizing access
110
+ // to inodes used by multiple processes. The cached
111
+ // inodes include book-keeping information that is
112
+ // not stored on disk: ip->ref and ip->flags.
109
113
//
110
114
// ip->ref counts the number of pointer references to this cached
111
115
// inode; references are typically kept in struct file and in proc->cwd.
@@ -114,11 +118,12 @@ bfree(int dev, uint b)
114
118
//
115
119
// Processes are only allowed to read and write inode
116
120
// metadata and contents when holding the inode's lock,
117
- // represented by the I_BUSY flag in the in-memory copy .
121
+ // represented by the I_BUSY bit in ip->flags .
118
122
// Because inode locks are held during disk accesses,
119
123
// they are implemented using a flag rather than with
120
- // spin locks. Callers are responsible for locking
121
- // inodes before passing them to routines in this file; leaving
124
+ // spin locks. ilock() and iunlock() manipulate an
125
+ // inode's I_BUSY flag. Many routines in this file expect
126
+ // the caller to have already locked the inode; leaving
122
127
// this responsibility with the caller makes it possible for them
123
128
// to create arbitrarily-sized atomic operations.
124
129
//
@@ -127,6 +132,19 @@ bfree(int dev, uint b)
127
132
// return pointers to *unlocked* inodes. It is the callers'
128
133
// responsibility to lock them before using them. A non-zero
129
134
// ip->ref keeps these unlocked inodes in the cache.
135
+ //
136
+ // In order for the file system code to look at an inode, the inode
137
+ // must pass through a number of states, with transitions
138
+ // driven by the indicated functions:
139
+ //
140
+ // * Allocated on disk, indicated by a non-zero type.
141
+ // ialloc() and iput().
142
+ // * Referenced in the cache, indicated by ip->ref > 0.
143
+ // iget() and iput().
144
+ // * Cached inode is valid, indicated by I_VALID.
145
+ // ilock() and iput().
146
+ // * Locked, indicated by I_BUSY.
147
+ // ilock() and iunlock().
130
148
131
149
struct {
132
150
struct spinlock lock ;
@@ -143,6 +161,7 @@ static struct inode* iget(uint dev, uint inum);
143
161
144
162
//PAGEBREAK!
145
163
// Allocate a new inode with the given type on device dev.
164
+ // A free inode has a type of zero.
146
165
struct inode *
147
166
ialloc (uint dev , short type )
148
167
{
@@ -152,7 +171,8 @@ ialloc(uint dev, short type)
152
171
struct superblock sb ;
153
172
154
173
readsb (dev , & sb );
155
- for (inum = 1 ; inum < sb .ninodes ; inum ++ ){ // loop over inode blocks
174
+
175
+ for (inum = 1 ; inum < sb .ninodes ; inum ++ ){
156
176
bp = bread (dev , IBLOCK (inum ));
157
177
dip = (struct dinode * )bp -> data + inum %IPB ;
158
178
if (dip -> type == 0 ){ // a free inode
0 commit comments