Skip to content

Commit a5fbfe4

Browse files
author
Robert Morris
committed
clarify some FS comments
1 parent d73dd09 commit a5fbfe4

File tree

6 files changed

+69
-46
lines changed

6 files changed

+69
-46
lines changed

bio.c

+8-8
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//
88
// Interface:
99
// * To get a buffer for a particular disk block, call bread.
10-
// * After changing buffer data, call bwrite to flush it to disk.
10+
// * After changing buffer data, call bwrite to write it to disk.
1111
// * When done with the buffer, call brelse.
1212
// * Do not use the buffer after calling brelse.
1313
// * Only one process at a time can use a buffer,
@@ -16,8 +16,7 @@
1616
// The implementation uses three state flags internally:
1717
// * B_BUSY: the block has been returned from bread
1818
// and has not been passed back to brelse.
19-
// * B_VALID: the buffer data has been initialized
20-
// with the associated disk block contents.
19+
// * B_VALID: the buffer data has been read from the disk.
2120
// * B_DIRTY: the buffer data has been modified
2221
// and needs to be written to disk.
2322

@@ -58,7 +57,7 @@ binit(void)
5857

5958
// Look through buffer cache for sector on device dev.
6059
// If not found, allocate fresh block.
61-
// In either case, return locked buffer.
60+
// In either case, return B_BUSY buffer.
6261
static struct buf*
6362
bget(uint dev, uint sector)
6463
{
@@ -67,7 +66,7 @@ bget(uint dev, uint sector)
6766
acquire(&bcache.lock);
6867

6968
loop:
70-
// Try for cached block.
69+
// Is the sector already cached?
7170
for(b = bcache.head.next; b != &bcache.head; b = b->next){
7271
if(b->dev == dev && b->sector == sector){
7372
if(!(b->flags & B_BUSY)){
@@ -80,7 +79,7 @@ bget(uint dev, uint sector)
8079
}
8180
}
8281

83-
// Allocate fresh block.
82+
// Not cached; recycle some existing buffer.
8483
for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
8584
if((b->flags & B_BUSY) == 0){
8685
b->dev = dev;
@@ -105,7 +104,7 @@ bread(uint dev, uint sector)
105104
return b;
106105
}
107106

108-
// Write b's contents to disk. Must be locked.
107+
// Write b's contents to disk. Must be B_BUSY.
109108
void
110109
bwrite(struct buf *b)
111110
{
@@ -115,7 +114,8 @@ bwrite(struct buf *b)
115114
iderw(b);
116115
}
117116

118-
// Release the buffer b.
117+
// Release a B_BUSY buffer.
118+
// Move to the head of the MRU list.
119119
void
120120
brelse(struct buf *b)
121121
{

file.h

+3-5
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ struct file {
99
};
1010

1111

12-
// in-core file system types
13-
12+
// in-memory copy of an inode
1413
struct inode {
1514
uint dev; // Device number
1615
uint inum; // Inode number
@@ -24,12 +23,11 @@ struct inode {
2423
uint size;
2524
uint addrs[NDIRECT+1];
2625
};
27-
2826
#define I_BUSY 0x1
2927
#define I_VALID 0x2
3028

31-
// device implementations
32-
29+
// table mapping major device number to
30+
// device functions
3331
struct devsw {
3432
int (*read)(struct inode*, char*, int);
3533
int (*write)(struct inode*, char*, int);

fs.c

+37-17
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
// File system implementation. Four layers:
1+
// File system implementation. Five layers:
22
// + Blocks: allocator for raw disk blocks.
3+
// + Log: crash recovery for multi-step updates.
34
// + Files: inode allocator, reading, writing, metadata.
45
// + Directories: inode with special contents (list of other inodes!)
56
// + Names: paths like /usr/rtm/xv6/fs.c for convenient naming.
67
//
7-
// Disk layout is: superblock, inodes, block in-use bitmap, data blocks.
8-
//
98
// This file contains the low-level file system manipulation
109
// routines. The (higher-level) system call implementations
1110
// are in sysfile.c.
@@ -61,10 +60,10 @@ balloc(uint dev)
6160
readsb(dev, &sb);
6261
for(b = 0; b < sb.size; b += BPB){
6362
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++){
6564
m = 1 << (bi % 8);
6665
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.
6867
log_write(bp);
6968
brelse(bp);
7069
bzero(dev, b + bi);
@@ -90,22 +89,27 @@ bfree(int dev, uint b)
9089
m = 1 << (bi % 8);
9190
if((bp->data[bi/8] & m) == 0)
9291
panic("freeing free block");
93-
bp->data[bi/8] &= ~m; // Mark block free on disk.
92+
bp->data[bi/8] &= ~m;
9493
log_write(bp);
9594
brelse(bp);
9695
}
9796

9897
// Inodes.
9998
//
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.
104103
//
105104
// 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.
109113
//
110114
// ip->ref counts the number of pointer references to this cached
111115
// inode; references are typically kept in struct file and in proc->cwd.
@@ -114,11 +118,12 @@ bfree(int dev, uint b)
114118
//
115119
// Processes are only allowed to read and write inode
116120
// 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.
118122
// Because inode locks are held during disk accesses,
119123
// 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
122127
// this responsibility with the caller makes it possible for them
123128
// to create arbitrarily-sized atomic operations.
124129
//
@@ -127,6 +132,19 @@ bfree(int dev, uint b)
127132
// return pointers to *unlocked* inodes. It is the callers'
128133
// responsibility to lock them before using them. A non-zero
129134
// 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().
130148

131149
struct {
132150
struct spinlock lock;
@@ -143,6 +161,7 @@ static struct inode* iget(uint dev, uint inum);
143161

144162
//PAGEBREAK!
145163
// Allocate a new inode with the given type on device dev.
164+
// A free inode has a type of zero.
146165
struct inode*
147166
ialloc(uint dev, short type)
148167
{
@@ -152,7 +171,8 @@ ialloc(uint dev, short type)
152171
struct superblock sb;
153172

154173
readsb(dev, &sb);
155-
for(inum = 1; inum < sb.ninodes; inum++){ // loop over inode blocks
174+
175+
for(inum = 1; inum < sb.ninodes; inum++){
156176
bp = bread(dev, IBLOCK(inum));
157177
dip = (struct dinode*)bp->data + inum%IPB;
158178
if(dip->type == 0){ // a free inode

fs.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
// On-disk file system format.
22
// Both the kernel and user programs use this header file.
33

4-
// Block 0 is unused. Block 1 is super block.
5-
// Inodes start at block 2.
4+
// Block 0 is unused.
5+
// Block 1 is super block.
6+
// Blocks 2 through sb.ninodes/IPB hold inodes.
7+
// Then free bitmap blocks holding sb.size bits.
8+
// Then sb.nblocks data blocks.
9+
// Then sb.nlog log blocks.
610

711
#define ROOTINO 1 // root i-number
812
#define BSIZE 512 // block size

ide.c

+3-4
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ ideintr(void)
9393
{
9494
struct buf *b;
9595

96-
// Take first buffer off queue.
96+
// First queued buffer is the active request.
9797
acquire(&idelock);
9898
if((b = idequeue) == 0){
9999
release(&idelock);
@@ -134,11 +134,11 @@ iderw(struct buf *b)
134134
if(b->dev != 0 && !havedisk1)
135135
panic("iderw: ide disk 1 not present");
136136

137-
acquire(&idelock); // DOC:acquire-lock
137+
acquire(&idelock); //DOC: acquire-lock
138138

139139
// Append b to idequeue.
140140
b->qnext = 0;
141-
for(pp=&idequeue; *pp; pp=&(*pp)->qnext) // DOC:insert-queue
141+
for(pp=&idequeue; *pp; pp=&(*pp)->qnext) //DOC: insert-queue
142142
;
143143
*pp = b;
144144

@@ -147,7 +147,6 @@ iderw(struct buf *b)
147147
idestart(b);
148148

149149
// Wait for request to finish.
150-
// Assuming will not sleep too long: ignore proc->killed.
151150
while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){
152151
sleep(b, &idelock);
153152
}

log.c

+12-10
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ struct log {
4242
struct spinlock lock;
4343
int start;
4444
int size;
45-
int intrans;
45+
int busy; // a transaction is active
4646
int dev;
4747
struct logheader lh;
4848
};
@@ -75,7 +75,7 @@ install_trans(void)
7575
struct buf *lbuf = bread(log.dev, log.start+tail+1); // read log block
7676
struct buf *dbuf = bread(log.dev, log.lh.sector[tail]); // read dst
7777
memmove(dbuf->data, lbuf->data, BSIZE); // copy block to dst
78-
bwrite(dbuf); // flush dst to disk
78+
bwrite(dbuf); // write dst to disk
7979
brelse(lbuf);
8080
brelse(dbuf);
8181
}
@@ -95,7 +95,9 @@ read_head(void)
9595
brelse(buf);
9696
}
9797

98-
// Write in-memory log header to disk, committing log entries till head
98+
// Write in-memory log header to disk.
99+
// This is the true point at which the
100+
// current transaction commits.
99101
static void
100102
write_head(void)
101103
{
@@ -123,25 +125,25 @@ void
123125
begin_trans(void)
124126
{
125127
acquire(&log.lock);
126-
while (log.intrans) {
128+
while (log.busy) {
127129
sleep(&log, &log.lock);
128130
}
129-
log.intrans = 1;
131+
log.busy = 1;
130132
release(&log.lock);
131133
}
132134

133135
void
134136
commit_trans(void)
135137
{
136138
if (log.lh.n > 0) {
137-
write_head(); // Causes all blocks till log.head to be commited
138-
install_trans(); // Install all the transactions till head
139+
write_head(); // Write header to disk -- the real commit
140+
install_trans(); // Now install writes to home locations
139141
log.lh.n = 0;
140-
write_head(); // Reclaim log
142+
write_head(); // Erase the transaction from the log
141143
}
142144

143145
acquire(&log.lock);
144-
log.intrans = 0;
146+
log.busy = 0;
145147
wakeup(&log);
146148
release(&log.lock);
147149
}
@@ -161,7 +163,7 @@ log_write(struct buf *b)
161163

162164
if (log.lh.n >= LOGSIZE || log.lh.n >= log.size - 1)
163165
panic("too big a transaction");
164-
if (!log.intrans)
166+
if (!log.busy)
165167
panic("write outside of trans");
166168

167169
for (i = 0; i < log.lh.n; i++) {

0 commit comments

Comments
 (0)